Skip to content

Commit f35bbad

Browse files
committed
fix problems with type checking
1 parent 82d4d1f commit f35bbad

File tree

3 files changed

+200
-186
lines changed

3 files changed

+200
-186
lines changed

compiler/rustc_hir_analysis/src/check/compare_eii.rs

Lines changed: 115 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
//! This module is very similar to `compare_impl_item`.
2+
//! Most logic is taken from there,
3+
//! since in a very similar way we're comparing some declaration of a signature to an implementation.
4+
//! The major difference is that we don't bother with self types, since for EIIs we're comparing freestanding item.
5+
16
use std::borrow::Cow;
27
use std::iter;
38

@@ -8,14 +13,15 @@ use rustc_hir::{self as hir, FnSig, HirId, ItemKind};
813
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
914
use rustc_infer::traits::{ObligationCause, ObligationCauseCode};
1015
use rustc_middle::ty::error::{ExpectedFound, TypeError};
11-
use rustc_middle::ty::{self, TyCtxt, TypingMode};
16+
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode};
1217
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
1318
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
1419
use rustc_trait_selection::regions::InferCtxtRegionExt;
15-
use rustc_trait_selection::traits::ObligationCtxt;
20+
use rustc_trait_selection::traits::{self, ObligationCtxt};
1621
use tracing::{debug, instrument};
1722

1823
use super::potentially_plural_count;
24+
use crate::check::compare_impl_item::{CheckRegionBoundsOnItemOutput, check_region_bounds_on_item};
1925
use crate::errors::{EiiWithGenerics, LifetimesOrBoundsMismatchOnEii};
2026

2127
/// checks whether the signature of some `external_impl`, matches
@@ -58,15 +64,15 @@ pub(crate) fn compare_eii_function_types<'tcx>(
5864
let declaration_sig = infcx.enter_forall_and_leak_universe(declaration_sig);
5965
let declaration_sig = ocx.normalize(&norm_cause, param_env, declaration_sig);
6066

61-
let external_impl_sig = infcx.instantiate_binder_with_fresh_vars(
67+
let unnormalized_external_impl_sig = infcx.instantiate_binder_with_fresh_vars(
6268
external_impl_span,
6369
infer::BoundRegionConversionTime::HigherRankedType,
6470
tcx.fn_sig(external_impl).instantiate(
6571
tcx,
6672
infcx.fresh_args_for_item(external_impl_span, external_impl.to_def_id()),
6773
),
6874
);
69-
let external_impl_sig = ocx.normalize(&norm_cause, param_env, external_impl_sig);
75+
let external_impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_external_impl_sig);
7076
debug!(?external_impl_sig);
7177

7278
// FIXME: We'd want to keep more accurate spans than "the method signature" when
@@ -93,6 +99,17 @@ pub(crate) fn compare_eii_function_types<'tcx>(
9399
return Err(emitted);
94100
}
95101

102+
if !(declaration_sig, external_impl_sig).references_error() {
103+
for ty in unnormalized_external_impl_sig.inputs_and_output {
104+
ocx.register_obligation(traits::Obligation::new(
105+
infcx.tcx,
106+
cause.clone(),
107+
param_env,
108+
ty::ClauseKind::WellFormed(ty.into()),
109+
));
110+
}
111+
}
112+
96113
// Check that all obligations are satisfied by the implementation's
97114
// version.
98115
let errors = ocx.select_all_or_error();
@@ -116,6 +133,8 @@ pub(crate) fn compare_eii_function_types<'tcx>(
116133
/// Checks a bunch of different properties of the impl/trait methods for
117134
/// compatibility, such as asyncness, number of argument, self receiver kind,
118135
/// and number of early- and late-bound generics.
136+
///
137+
/// Corresponds to `check_method_is_structurally_compatible` for impl method compatibility checks.
119138
fn check_is_structurally_compatible<'tcx>(
120139
tcx: TyCtxt<'tcx>,
121140
external_impl: LocalDefId,
@@ -125,7 +144,7 @@ fn check_is_structurally_compatible<'tcx>(
125144
) -> Result<(), ErrorGuaranteed> {
126145
check_no_generics(tcx, external_impl, declaration, eii_name, eii_attr_span)?;
127146
compare_number_of_method_arguments(tcx, external_impl, declaration, eii_name, eii_attr_span)?;
128-
check_region_bounds_on_impl_item(tcx, external_impl, declaration, eii_attr_span)?;
147+
check_region_bounds_on_eii(tcx, external_impl, declaration, eii_attr_span)?;
129148
Ok(())
130149
}
131150

@@ -148,6 +167,44 @@ fn check_no_generics<'tcx>(
148167
Ok(())
149168
}
150169

170+
fn check_region_bounds_on_eii<'tcx>(
171+
tcx: TyCtxt<'tcx>,
172+
external_impl: LocalDefId,
173+
declaration: DefId,
174+
eii_attr_span: Span,
175+
) -> Result<(), ErrorGuaranteed> {
176+
let external_impl_generics = tcx.generics_of(external_impl.to_def_id());
177+
let external_impl_params = external_impl_generics.own_counts().lifetimes;
178+
179+
let declaration_generics = tcx.generics_of(declaration);
180+
let declaration_params = declaration_generics.own_counts().lifetimes;
181+
182+
let Some(CheckRegionBoundsOnItemOutput { span, generics_span, bounds_span, where_span }) =
183+
check_region_bounds_on_item(
184+
tcx,
185+
external_impl,
186+
declaration,
187+
external_impl_generics,
188+
external_impl_params,
189+
declaration_generics,
190+
declaration_params,
191+
)
192+
else {
193+
return Ok(());
194+
};
195+
196+
let mut diag = tcx.dcx().create_err(LifetimesOrBoundsMismatchOnEii {
197+
span,
198+
ident: tcx.item_name(external_impl.to_def_id()),
199+
generics_span,
200+
bounds_span,
201+
where_span,
202+
});
203+
204+
diag.span_label(eii_attr_span, format!("required because of this attribute"));
205+
return Err(diag.emit());
206+
}
207+
151208
fn compare_number_of_method_arguments<'tcx>(
152209
tcx: TyCtxt<'tcx>,
153210
external_impl: LocalDefId,
@@ -159,152 +216,71 @@ fn compare_number_of_method_arguments<'tcx>(
159216
let declaration_fty = tcx.fn_sig(declaration);
160217
let declaration_number_args = declaration_fty.skip_binder().inputs().skip_binder().len();
161218
let external_impl_number_args = external_impl_fty.skip_binder().inputs().skip_binder().len();
219+
220+
// if the number of args are equal, we're trivially done
221+
if declaration_number_args == external_impl_number_args {
222+
return Ok(());
223+
}
224+
162225
let external_impl_name = tcx.item_name(external_impl.to_def_id());
163226

164-
if declaration_number_args != external_impl_number_args {
165-
let declaration_span = declaration
166-
.as_local()
167-
.and_then(|def_id| {
168-
let declaration_sig = get_declaration_sig(tcx, def_id).expect("foreign item sig");
169-
let pos = declaration_number_args.saturating_sub(1);
170-
declaration_sig.decl.inputs.get(pos).map(|arg| {
171-
if pos == 0 {
172-
arg.span
173-
} else {
174-
arg.span.with_lo(declaration_sig.decl.inputs[0].span.lo())
175-
}
176-
})
177-
})
178-
.or_else(|| tcx.hir_span_if_local(declaration))
179-
.unwrap_or_else(|| tcx.def_span(declaration));
180-
181-
let (_, external_impl_sig, _, _) = &tcx.hir_expect_item(external_impl).expect_fn();
182-
let pos = external_impl_number_args.saturating_sub(1);
183-
let impl_span = external_impl_sig
184-
.decl
185-
.inputs
186-
.get(pos)
187-
.map(|arg| {
227+
let declaration_span = declaration
228+
.as_local()
229+
.and_then(|def_id| {
230+
let declaration_sig = get_declaration_sig(tcx, def_id).expect("foreign item sig");
231+
let pos = declaration_number_args.saturating_sub(1);
232+
declaration_sig.decl.inputs.get(pos).map(|arg| {
188233
if pos == 0 {
189234
arg.span
190235
} else {
191-
arg.span.with_lo(external_impl_sig.decl.inputs[0].span.lo())
236+
arg.span.with_lo(declaration_sig.decl.inputs[0].span.lo())
192237
}
193238
})
194-
.unwrap_or_else(|| tcx.def_span(external_impl));
195-
196-
let mut err = struct_span_code_err!(
197-
tcx.dcx(),
198-
impl_span,
199-
E0805,
200-
"`{external_impl_name}` has {} but #[{eii_name}] requires it to have {}",
201-
potentially_plural_count(external_impl_number_args, "parameter"),
202-
declaration_number_args
203-
);
204-
205-
// if let Some(declaration_span) = declaration_span {
206-
err.span_label(
207-
declaration_span,
208-
format!("requires {}", potentially_plural_count(declaration_number_args, "parameter")),
209-
);
210-
// }
211-
212-
err.span_label(
213-
impl_span,
214-
format!(
215-
"expected {}, found {}",
216-
potentially_plural_count(declaration_number_args, "parameter"),
217-
external_impl_number_args
218-
),
219-
);
220-
221-
err.span_label(eii_attr_span, format!("required because of this attribute"));
222-
223-
return Err(err.emit());
224-
}
225-
226-
Ok(())
227-
}
239+
})
240+
.or_else(|| tcx.hir_span_if_local(declaration))
241+
.unwrap_or_else(|| tcx.def_span(declaration));
242+
243+
let (_, external_impl_sig, _, _) = &tcx.hir_expect_item(external_impl).expect_fn();
244+
let pos = external_impl_number_args.saturating_sub(1);
245+
let impl_span = external_impl_sig
246+
.decl
247+
.inputs
248+
.get(pos)
249+
.map(|arg| {
250+
if pos == 0 {
251+
arg.span
252+
} else {
253+
arg.span.with_lo(external_impl_sig.decl.inputs[0].span.lo())
254+
}
255+
})
256+
.unwrap_or_else(|| tcx.def_span(external_impl));
228257

229-
fn check_region_bounds_on_impl_item<'tcx>(
230-
tcx: TyCtxt<'tcx>,
231-
external_impl: LocalDefId,
232-
declaration: DefId,
233-
eii_attr_span: Span,
234-
) -> Result<(), ErrorGuaranteed> {
235-
let external_impl_generics = tcx.generics_of(external_impl.to_def_id());
236-
let external_impl_params = external_impl_generics.own_counts().lifetimes;
258+
let mut err = struct_span_code_err!(
259+
tcx.dcx(),
260+
impl_span,
261+
E0805,
262+
"`{external_impl_name}` has {} but #[{eii_name}] requires it to have {}",
263+
potentially_plural_count(external_impl_number_args, "parameter"),
264+
declaration_number_args
265+
);
237266

238-
let declaration_generics = tcx.generics_of(declaration);
239-
let declaration_params = declaration_generics.own_counts().lifetimes;
267+
err.span_label(
268+
declaration_span,
269+
format!("requires {}", potentially_plural_count(declaration_number_args, "parameter")),
270+
);
240271

241-
debug!(?declaration_generics, ?external_impl_generics);
242-
243-
// Must have same number of early-bound lifetime parameters.
244-
// Unfortunately, if the user screws up the bounds, then this
245-
// will change classification between early and late. E.g.,
246-
// if in trait we have `<'a,'b:'a>`, and in impl we just have
247-
// `<'a,'b>`, then we have 2 early-bound lifetime parameters
248-
// in trait but 0 in the impl. But if we report "expected 2
249-
// but found 0" it's confusing, because it looks like there
250-
// are zero. Since I don't quite know how to phrase things at
251-
// the moment, give a kind of vague error message.
252-
if declaration_params != external_impl_params {
253-
let span = tcx
254-
.hir_get_generics(external_impl)
255-
.expect("expected impl item to have generics or else we can't compare them")
256-
.span;
257-
258-
let mut generics_span = None;
259-
let mut bounds_span = vec![];
260-
let mut where_span = None;
261-
262-
if let Some(declaration_node) = tcx.hir_get_if_local(declaration)
263-
&& let Some(declaration_generics) = declaration_node.generics()
264-
{
265-
generics_span = Some(declaration_generics.span);
266-
// FIXME: we could potentially look at the impl's bounds to not point at bounds that
267-
// *are* present in the impl.
268-
for p in declaration_generics.predicates {
269-
if let hir::WherePredicateKind::BoundPredicate(pred) = p.kind {
270-
for b in pred.bounds {
271-
if let hir::GenericBound::Outlives(lt) = b {
272-
bounds_span.push(lt.ident.span);
273-
}
274-
}
275-
}
276-
}
277-
if let Some(implementation_generics) = tcx.hir_get_generics(external_impl) {
278-
let mut impl_bounds = 0;
279-
for p in implementation_generics.predicates {
280-
if let hir::WherePredicateKind::BoundPredicate(pred) = p.kind {
281-
for b in pred.bounds {
282-
if let hir::GenericBound::Outlives(_) = b {
283-
impl_bounds += 1;
284-
}
285-
}
286-
}
287-
}
288-
if impl_bounds == bounds_span.len() {
289-
bounds_span = vec![];
290-
} else if implementation_generics.has_where_clause_predicates {
291-
where_span = Some(implementation_generics.where_clause_span);
292-
}
293-
}
294-
}
295-
let mut diag = tcx.dcx().create_err(LifetimesOrBoundsMismatchOnEii {
296-
span,
297-
ident: tcx.item_name(external_impl.to_def_id()),
298-
generics_span,
299-
bounds_span,
300-
where_span,
301-
});
272+
err.span_label(
273+
impl_span,
274+
format!(
275+
"expected {}, found {}",
276+
potentially_plural_count(declaration_number_args, "parameter"),
277+
external_impl_number_args
278+
),
279+
);
302280

303-
diag.span_label(eii_attr_span, format!("required because of this attribute"));
304-
return Err(diag.emit());
305-
}
281+
err.span_label(eii_attr_span, format!("required because of this attribute"));
306282

307-
Ok(())
283+
Err(err.emit())
308284
}
309285

310286
fn report_eii_mismatch<'tcx>(

0 commit comments

Comments
 (0)