flux_refineck/
compare_impl_item.rs1use flux_common::result::ErrorEmitter;
2use flux_infer::{
3 infer::{GlobalEnvExt as _, InferCtxt},
4 projections::NormalizeExt as _,
5};
6use flux_middle::{
7 def_id::{FluxDefId, MaybeExternId},
8 def_id_to_string,
9 global_env::GlobalEnv,
10 queries::QueryResult,
11 rty::TraitRef,
12};
13use rustc_hash::FxHashSet;
14use rustc_infer::infer::TyCtxtInferExt;
15use rustc_middle::ty::TypingMode;
16
17pub fn check_impl_against_trait(genv: GlobalEnv, impl_id: MaybeExternId) -> QueryResult {
18 let trait_id = genv.tcx().impl_trait_id(impl_id.resolved_id());
19
20 let impl_assoc_refts = genv.assoc_refinements_of(impl_id)?;
21 let trait_assoc_refts = genv.assoc_refinements_of(trait_id)?;
22 let impl_names: FxHashSet<_> = impl_assoc_refts.items.iter().map(|x| x.name()).collect();
23
24 for trait_assoc_reft in &trait_assoc_refts.items {
25 let trait_assoc_def_id = trait_assoc_reft.def_id();
26 let has_default = genv
27 .default_assoc_refinement_body(trait_assoc_def_id)?
28 .is_some();
29 if !impl_names.contains(&trait_assoc_reft.name()) && !has_default {
30 let span = genv.tcx().def_span(impl_id);
31 Err(genv.emit(errors::MissingAssocReft::new(span, trait_assoc_reft.name())))?;
32 } else if impl_names.contains(&trait_assoc_reft.name()) && trait_assoc_reft.final_ {
33 let span = genv.tcx().def_span(impl_id);
34 Err(genv.emit(errors::ImplAssocReftOnFinal::new(span, trait_assoc_reft.name())))?;
35 }
36 }
37
38 let impl_trait_ref = genv
39 .impl_trait_ref(impl_id.resolved_id())?
40 .instantiate_identity();
41
42 let rustc_infcx = genv
43 .tcx()
44 .infer_ctxt()
45 .with_next_trait_solver(true)
46 .build(TypingMode::non_body_analysis());
47 let mut root_ctxt = genv
48 .infcx_root(&rustc_infcx, genv.infer_opts(impl_id.local_id()))
49 .with_const_generics(impl_id.resolved_id())?
50 .build()?;
51 let mut infcx = root_ctxt.infcx(impl_id.resolved_id(), &rustc_infcx);
52
53 for impl_assoc_reft in &impl_assoc_refts.items {
54 let name = impl_assoc_reft.name();
55 if let Some(trait_assoc_reft) = trait_assoc_refts.find(name) {
56 check_assoc_reft(
57 &mut infcx,
58 impl_id,
59 &impl_trait_ref,
60 trait_assoc_reft.def_id(),
61 impl_assoc_reft.def_id(),
62 )?;
63 } else {
64 let fhir_impl_assoc_reft = genv
65 .fhir_expect_item(impl_id.local_id())?
66 .expect_impl()
67 .find_assoc_reft(name)
68 .unwrap();
69 Err(genv.emit(errors::InvalidAssocReft::new(
70 fhir_impl_assoc_reft.span,
71 name,
72 def_id_to_string(trait_id),
73 )))?;
74 }
75 }
76
77 Ok(())
78}
79
80fn check_assoc_reft(
81 infcx: &mut InferCtxt,
82 impl_id: MaybeExternId,
83 impl_trait_ref: &TraitRef,
84 trait_assoc_id: FluxDefId,
85 impl_assoc_id: FluxDefId,
86) -> QueryResult {
87 debug_assert_eq!(trait_assoc_id.name(), impl_assoc_id.name());
88
89 let impl_span = infcx
90 .genv
91 .fhir_expect_item(impl_id.local_id())?
92 .expect_impl()
93 .find_assoc_reft(impl_assoc_id.name())
94 .unwrap()
95 .span;
96
97 let impl_sort = infcx
98 .genv
99 .sort_of_assoc_reft(impl_assoc_id)?
100 .instantiate_identity()
101 .deeply_normalize(&mut infcx.at(impl_span))?;
102
103 let trait_sort = infcx.genv.sort_of_assoc_reft(trait_assoc_id)?;
104 let trait_sort = trait_sort.instantiate(infcx.tcx(), &impl_trait_ref.args, &[]);
105 let trait_sort = trait_sort.deeply_normalize(&mut infcx.at(impl_span))?;
106
107 if impl_sort != trait_sort {
108 Err(infcx.genv.emit(errors::IncompatibleSort::new(
109 impl_span,
110 impl_assoc_id.name(),
111 trait_sort,
112 impl_sort,
113 )))?;
114 }
115
116 Ok(())
117}
118
119pub(crate) mod errors {
120 use flux_errors::E0999;
121 use flux_macros::Diagnostic;
122 use flux_middle::rty;
123 use rustc_span::{Span, Symbol};
124
125 #[derive(Diagnostic)]
126 #[diag(refineck_incompatible_sort, code = E0999)]
127 pub(super) struct IncompatibleSort {
128 #[primary_span]
129 #[label]
130 span: Span,
131 name: Symbol,
132 expected: rty::FuncSort,
133 found: rty::FuncSort,
134 }
135
136 impl IncompatibleSort {
137 pub(super) fn new(
138 span: Span,
139 name: Symbol,
140 expected: rty::FuncSort,
141 found: rty::FuncSort,
142 ) -> Self {
143 Self { span, name, expected, found }
144 }
145 }
146
147 #[derive(Diagnostic)]
148 #[diag(refineck_missing_assoc_reft, code = E0999)]
149 pub struct MissingAssocReft {
150 #[primary_span]
151 span: Span,
152 name: Symbol,
153 }
154
155 impl MissingAssocReft {
156 pub(crate) fn new(span: Span, name: Symbol) -> Self {
157 Self { span, name }
158 }
159 }
160
161 #[derive(Diagnostic)]
162 #[diag(refineck_impl_assoc_reft_final, code = E0999)]
163 pub struct ImplAssocReftOnFinal {
164 #[primary_span]
165 span: Span,
166 name: Symbol,
167 }
168
169 impl ImplAssocReftOnFinal {
170 pub(crate) fn new(span: Span, name: Symbol) -> Self {
171 Self { span, name }
172 }
173 }
174
175 #[derive(Diagnostic)]
176 #[diag(refineck_invalid_assoc_reft, code = E0999)]
177 pub struct InvalidAssocReft {
178 #[primary_span]
179 span: Span,
180 trait_: String,
181 name: Symbol,
182 }
183
184 impl InvalidAssocReft {
185 pub(crate) fn new(span: Span, name: Symbol, trait_: String) -> Self {
186 Self { span, trait_, name }
187 }
188 }
189}