Skip to content

Commit 761c504

Browse files
authored
Unrolled build for rust-lang#121863
Rollup merge of rust-lang#121863 - lukas-code:silence-mismatched-super-projections, r=lcnr silence mismatched types errors for implied projections Currently, if a trait bound is not satisfied, then we suppress any errors for the trait's supertraits not being satisfied, but still report errors for super projections not being satisfied. For example: ```rust trait Super { type Assoc; } trait Sub: Super<Assoc = ()> {} ``` Before this PR, if `T: Sub` is not satisfied, then errors for `T: Super` are suppressed, but errors for `<T as Super>::Assoc == ()` are still shown. This PR makes it so that errors about super projections not being satisfied are also suppressed. The errors are only suppressed if the span of the trait obligation matches the span of the super predicate obligation to avoid silencing error that are not related. This PR removes some differences between the spans of supertraits and super projections to make the suppression work correctly. This PR fixes the majority of the diagnostics fallout when making `Thin` a supertrait of `Sized` (in a future PR). cc rust-lang#120354 (comment) cc `@lcnr`
2 parents 52f8aec + db48b93 commit 761c504

File tree

10 files changed

+310
-102
lines changed

10 files changed

+310
-102
lines changed

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+28-18
Original file line numberDiff line numberDiff line change
@@ -298,31 +298,31 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
298298
hir::ItemKind::Const(ty, ..) => {
299299
check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid)
300300
}
301-
hir::ItemKind::Struct(_, ast_generics) => {
301+
hir::ItemKind::Struct(_, hir_generics) => {
302302
let res = check_type_defn(tcx, item, false);
303-
check_variances_for_type_defn(tcx, item, ast_generics);
303+
check_variances_for_type_defn(tcx, item, hir_generics);
304304
res
305305
}
306-
hir::ItemKind::Union(_, ast_generics) => {
306+
hir::ItemKind::Union(_, hir_generics) => {
307307
let res = check_type_defn(tcx, item, true);
308-
check_variances_for_type_defn(tcx, item, ast_generics);
308+
check_variances_for_type_defn(tcx, item, hir_generics);
309309
res
310310
}
311-
hir::ItemKind::Enum(_, ast_generics) => {
311+
hir::ItemKind::Enum(_, hir_generics) => {
312312
let res = check_type_defn(tcx, item, true);
313-
check_variances_for_type_defn(tcx, item, ast_generics);
313+
check_variances_for_type_defn(tcx, item, hir_generics);
314314
res
315315
}
316316
hir::ItemKind::Trait(..) => check_trait(tcx, item),
317317
hir::ItemKind::TraitAlias(..) => check_trait(tcx, item),
318318
// `ForeignItem`s are handled separately.
319319
hir::ItemKind::ForeignMod { .. } => Ok(()),
320-
hir::ItemKind::TyAlias(hir_ty, ast_generics) => {
320+
hir::ItemKind::TyAlias(hir_ty, hir_generics) => {
321321
if tcx.type_alias_is_lazy(item.owner_id) {
322322
// Bounds of lazy type aliases and of eager ones that contain opaque types are respected.
323323
// E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`.
324324
let res = check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow);
325-
check_variances_for_type_defn(tcx, item, ast_generics);
325+
check_variances_for_type_defn(tcx, item, hir_generics);
326326
res
327327
} else {
328328
Ok(())
@@ -1277,25 +1277,26 @@ fn check_item_type(
12771277
})
12781278
}
12791279

1280-
#[instrument(level = "debug", skip(tcx, ast_self_ty, ast_trait_ref))]
1280+
#[instrument(level = "debug", skip(tcx, hir_self_ty, hir_trait_ref))]
12811281
fn check_impl<'tcx>(
12821282
tcx: TyCtxt<'tcx>,
12831283
item: &'tcx hir::Item<'tcx>,
1284-
ast_self_ty: &hir::Ty<'_>,
1285-
ast_trait_ref: &Option<hir::TraitRef<'_>>,
1284+
hir_self_ty: &hir::Ty<'_>,
1285+
hir_trait_ref: &Option<hir::TraitRef<'_>>,
12861286
) -> Result<(), ErrorGuaranteed> {
12871287
enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| {
1288-
match ast_trait_ref {
1289-
Some(ast_trait_ref) => {
1288+
match hir_trait_ref {
1289+
Some(hir_trait_ref) => {
12901290
// `#[rustc_reservation_impl]` impls are not real impls and
12911291
// therefore don't need to be WF (the trait's `Self: Trait` predicate
12921292
// won't hold).
12931293
let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap().instantiate_identity();
12941294
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
12951295
// other `Foo` impls are incoherent.
12961296
tcx.ensure().coherent_trait(trait_ref.def_id)?;
1297+
let trait_span = hir_trait_ref.path.span;
12971298
let trait_ref = wfcx.normalize(
1298-
ast_trait_ref.path.span,
1299+
trait_span,
12991300
Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
13001301
trait_ref,
13011302
);
@@ -1306,14 +1307,23 @@ fn check_impl<'tcx>(
13061307
wfcx.param_env,
13071308
wfcx.body_def_id,
13081309
trait_pred,
1309-
ast_trait_ref.path.span,
1310+
trait_span,
13101311
item,
13111312
);
13121313
for obligation in &mut obligations {
1314+
if obligation.cause.span != trait_span {
1315+
// We already have a better span.
1316+
continue;
1317+
}
13131318
if let Some(pred) = obligation.predicate.to_opt_poly_trait_pred()
1314-
&& pred.self_ty().skip_binder() == trait_ref.self_ty()
1319+
&& pred.skip_binder().self_ty() == trait_ref.self_ty()
1320+
{
1321+
obligation.cause.span = hir_self_ty.span;
1322+
}
1323+
if let Some(pred) = obligation.predicate.to_opt_poly_projection_pred()
1324+
&& pred.skip_binder().self_ty() == trait_ref.self_ty()
13151325
{
1316-
obligation.cause.span = ast_self_ty.span;
1326+
obligation.cause.span = hir_self_ty.span;
13171327
}
13181328
}
13191329
debug!(?obligations);
@@ -1327,7 +1337,7 @@ fn check_impl<'tcx>(
13271337
self_ty,
13281338
);
13291339
wfcx.register_wf_obligation(
1330-
ast_self_ty.span,
1340+
hir_self_ty.span,
13311341
Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
13321342
self_ty.into(),
13331343
);

compiler/rustc_infer/src/infer/relate/higher_ranked.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ impl<'tcx> InferCtxt<'tcx> {
7777
// that name placeholders created in this function. Nested goals from type relations can
7878
// also contain placeholders created by this function.
7979
let value = self.enter_forall_and_leak_universe(forall);
80-
debug!("?value");
80+
debug!(?value);
8181
f(value)
8282
}
8383

compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs

+50-31
Original file line numberDiff line numberDiff line change
@@ -1431,45 +1431,64 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
14311431

14321432
#[extension(pub(super) trait InferCtxtPrivExt<'tcx>)]
14331433
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
1434+
fn can_match_trait(
1435+
&self,
1436+
goal: ty::TraitPredicate<'tcx>,
1437+
assumption: ty::PolyTraitPredicate<'tcx>,
1438+
) -> bool {
1439+
if goal.polarity != assumption.polarity() {
1440+
return false;
1441+
}
1442+
1443+
let trait_goal = goal.trait_ref;
1444+
let trait_assumption = self.instantiate_binder_with_fresh_vars(
1445+
DUMMY_SP,
1446+
infer::BoundRegionConversionTime::HigherRankedType,
1447+
assumption.to_poly_trait_ref(),
1448+
);
1449+
1450+
self.can_eq(ty::ParamEnv::empty(), trait_goal, trait_assumption)
1451+
}
1452+
1453+
fn can_match_projection(
1454+
&self,
1455+
goal: ty::ProjectionPredicate<'tcx>,
1456+
assumption: ty::PolyProjectionPredicate<'tcx>,
1457+
) -> bool {
1458+
let assumption = self.instantiate_binder_with_fresh_vars(
1459+
DUMMY_SP,
1460+
infer::BoundRegionConversionTime::HigherRankedType,
1461+
assumption,
1462+
);
1463+
1464+
let param_env = ty::ParamEnv::empty();
1465+
self.can_eq(param_env, goal.projection_ty, assumption.projection_ty)
1466+
&& self.can_eq(param_env, goal.term, assumption.term)
1467+
}
1468+
14341469
// returns if `cond` not occurring implies that `error` does not occur - i.e., that
14351470
// `error` occurring implies that `cond` occurs.
1471+
#[instrument(level = "debug", skip(self), ret)]
14361472
fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool {
14371473
if cond == error {
14381474
return true;
14391475
}
14401476

1441-
// FIXME: It should be possible to deal with `ForAll` in a cleaner way.
1442-
let bound_error = error.kind();
1443-
let (cond, error) = match (cond.kind().skip_binder(), bound_error.skip_binder()) {
1444-
(
1445-
ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)),
1446-
ty::PredicateKind::Clause(ty::ClauseKind::Trait(error)),
1447-
) => (cond, bound_error.rebind(error)),
1448-
_ => {
1449-
// FIXME: make this work in other cases too.
1450-
return false;
1451-
}
1452-
};
1453-
1454-
for pred in elaborate(self.tcx, std::iter::once(cond)) {
1455-
let bound_predicate = pred.kind();
1456-
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(implication)) =
1457-
bound_predicate.skip_binder()
1458-
{
1459-
let error = error.to_poly_trait_ref();
1460-
let implication = bound_predicate.rebind(implication.trait_ref);
1461-
// FIXME: I'm just not taking associated types at all here.
1462-
// Eventually I'll need to implement param-env-aware
1463-
// `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic.
1464-
let param_env = ty::ParamEnv::empty();
1465-
if self.can_sub(param_env, error, implication) {
1466-
debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication);
1467-
return true;
1468-
}
1469-
}
1477+
if let Some(error) = error.to_opt_poly_trait_pred() {
1478+
self.enter_forall(error, |error| {
1479+
elaborate(self.tcx, std::iter::once(cond))
1480+
.filter_map(|implied| implied.to_opt_poly_trait_pred())
1481+
.any(|implied| self.can_match_trait(error, implied))
1482+
})
1483+
} else if let Some(error) = error.to_opt_poly_projection_pred() {
1484+
self.enter_forall(error, |error| {
1485+
elaborate(self.tcx, std::iter::once(cond))
1486+
.filter_map(|implied| implied.to_opt_poly_projection_pred())
1487+
.any(|implied| self.can_match_projection(error, implied))
1488+
})
1489+
} else {
1490+
false
14701491
}
1471-
1472-
false
14731492
}
14741493

14751494
#[instrument(skip(self), level = "debug")]

compiler/rustc_trait_selection/src/traits/wf.rs

+60-35
Original file line numberDiff line numberDiff line change
@@ -223,60 +223,87 @@ enum Elaborate {
223223
None,
224224
}
225225

226+
/// Points the cause span of a super predicate at the relevant associated type.
227+
///
228+
/// Given a trait impl item:
229+
///
230+
/// ```ignore (incomplete)
231+
/// impl TargetTrait for TargetType {
232+
/// type Assoc = SomeType;
233+
/// }
234+
/// ```
235+
///
236+
/// And a super predicate of `TargetTrait` that has any of the following forms:
237+
///
238+
/// 1. `<OtherType as OtherTrait>::Assoc == <TargetType as TargetTrait>::Assoc`
239+
/// 2. `<<TargetType as TargetTrait>::Assoc as OtherTrait>::Assoc == OtherType`
240+
/// 3. `<TargetType as TargetTrait>::Assoc: OtherTrait`
241+
///
242+
/// Replace the span of the cause with the span of the associated item:
243+
///
244+
/// ```ignore (incomplete)
245+
/// impl TargetTrait for TargetType {
246+
/// type Assoc = SomeType;
247+
/// // ^^^^^^^^ this span
248+
/// }
249+
/// ```
250+
///
251+
/// Note that bounds that can be expressed as associated item bounds are **not**
252+
/// super predicates. This means that form 2 and 3 from above are only relevant if
253+
/// the [`GenericArgsRef`] of the projection type are not its identity arguments.
226254
fn extend_cause_with_original_assoc_item_obligation<'tcx>(
227255
tcx: TyCtxt<'tcx>,
228-
trait_ref: ty::TraitRef<'tcx>,
229256
item: Option<&hir::Item<'tcx>>,
230257
cause: &mut traits::ObligationCause<'tcx>,
231258
pred: ty::Predicate<'tcx>,
232259
) {
233-
debug!(
234-
"extended_cause_with_original_assoc_item_obligation {:?} {:?} {:?} {:?}",
235-
trait_ref, item, cause, pred
236-
);
260+
debug!(?item, ?cause, ?pred, "extended_cause_with_original_assoc_item_obligation");
237261
let (items, impl_def_id) = match item {
238262
Some(hir::Item { kind: hir::ItemKind::Impl(impl_), owner_id, .. }) => {
239263
(impl_.items, *owner_id)
240264
}
241265
_ => return,
242266
};
243-
let fix_span =
244-
|impl_item_ref: &hir::ImplItemRef| match tcx.hir().impl_item(impl_item_ref.id).kind {
245-
hir::ImplItemKind::Const(ty, _) | hir::ImplItemKind::Type(ty) => ty.span,
246-
_ => impl_item_ref.span,
247-
};
267+
268+
let ty_to_impl_span = |ty: Ty<'_>| {
269+
if let ty::Alias(ty::Projection, projection_ty) = ty.kind()
270+
&& let Some(&impl_item_id) =
271+
tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.def_id)
272+
&& let Some(impl_item) =
273+
items.iter().find(|item| item.id.owner_id.to_def_id() == impl_item_id)
274+
{
275+
Some(tcx.hir().impl_item(impl_item.id).expect_type().span)
276+
} else {
277+
None
278+
}
279+
};
248280

249281
// It is fine to skip the binder as we don't care about regions here.
250282
match pred.kind().skip_binder() {
251283
ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) => {
252-
// The obligation comes not from the current `impl` nor the `trait` being implemented,
253-
// but rather from a "second order" obligation, where an associated type has a
254-
// projection coming from another associated type. See
255-
// `tests/ui/associated-types/point-at-type-on-obligation-failure.rs` and
256-
// `traits-assoc-type-in-supertrait-bad.rs`.
257-
if let Some(ty::Alias(ty::Projection, projection_ty)) =
258-
proj.term.ty().map(|ty| ty.kind())
259-
&& let Some(&impl_item_id) =
260-
tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.def_id)
261-
&& let Some(impl_item_span) = items
262-
.iter()
263-
.find(|item| item.id.owner_id.to_def_id() == impl_item_id)
264-
.map(fix_span)
284+
// Form 1: The obligation comes not from the current `impl` nor the `trait` being
285+
// implemented, but rather from a "second order" obligation, where an associated
286+
// type has a projection coming from another associated type.
287+
// See `tests/ui/traits/assoc-type-in-superbad.rs` for an example.
288+
if let Some(term_ty) = proj.term.ty()
289+
&& let Some(impl_item_span) = ty_to_impl_span(term_ty)
265290
{
266291
cause.span = impl_item_span;
267292
}
293+
294+
// Form 2: A projection obligation for an associated item failed to be met.
295+
// We overwrite the span from above to ensure that a bound like
296+
// `Self::Assoc1: Trait<OtherAssoc = Self::Assoc2>` gets the same
297+
// span for both obligations that it is lowered to.
298+
if let Some(impl_item_span) = ty_to_impl_span(proj.self_ty()) {
299+
cause.span = impl_item_span;
300+
}
268301
}
302+
269303
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
270-
// An associated item obligation born out of the `trait` failed to be met. An example
271-
// can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`.
304+
// Form 3: A trait obligation for an associated item failed to be met.
272305
debug!("extended_cause_with_original_assoc_item_obligation trait proj {:?}", pred);
273-
if let ty::Alias(ty::Projection, ty::AliasTy { def_id, .. }) = *pred.self_ty().kind()
274-
&& let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&def_id)
275-
&& let Some(impl_item_span) = items
276-
.iter()
277-
.find(|item| item.id.owner_id.to_def_id() == impl_item_id)
278-
.map(fix_span)
279-
{
306+
if let Some(impl_item_span) = ty_to_impl_span(pred.self_ty()) {
280307
cause.span = impl_item_span;
281308
}
282309
}
@@ -355,9 +382,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
355382
traits::ObligationCauseCode::DerivedObligation,
356383
);
357384
}
358-
extend_cause_with_original_assoc_item_obligation(
359-
tcx, trait_ref, item, &mut cause, predicate,
360-
);
385+
extend_cause_with_original_assoc_item_obligation(tcx, item, &mut cause, predicate);
361386
traits::Obligation::with_depth(tcx, cause, depth, param_env, predicate)
362387
};
363388

tests/ui/associated-types/hr-associated-type-projection-1.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ where
1111
}
1212

1313
impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T {
14-
//~^ type mismatch resolving `<T as Deref>::Target == T`
1514
type Item = T;
15+
//~^ type mismatch resolving `<T as Deref>::Target == T`
1616
}
1717

1818
pub fn main() {

tests/ui/associated-types/hr-associated-type-projection-1.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
error[E0271]: type mismatch resolving `<T as Deref>::Target == T`
2-
--> $DIR/hr-associated-type-projection-1.rs:13:33
2+
--> $DIR/hr-associated-type-projection-1.rs:14:17
33
|
44
LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T {
5-
| - ^^^^^^^^^^^^^^^^^ expected type parameter `T`, found associated type
6-
| |
7-
| expected this type parameter
5+
| - expected this type parameter
6+
LL | type Item = T;
7+
| ^ expected type parameter `T`, found associated type
88
|
99
= note: expected type parameter `T`
1010
found associated type `<T as Deref>::Target`

tests/ui/issues/issue-33941.rs

-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,4 @@ use std::collections::HashMap;
55
fn main() {
66
for _ in HashMap::new().iter().cloned() {} //~ ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
77
//~^ ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
8-
//~| ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
98
}

tests/ui/issues/issue-33941.stderr

+1-11
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,6 @@ LL | for _ in HashMap::new().iter().cloned() {}
2727
= note: required for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` to implement `Iterator`
2828
= note: required for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` to implement `IntoIterator`
2929

30-
error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
31-
--> $DIR/issue-33941.rs:6:14
32-
|
33-
LL | for _ in HashMap::new().iter().cloned() {}
34-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(&_, &_)`, found `&_`
35-
|
36-
= note: expected tuple `(&_, &_)`
37-
found reference `&_`
38-
= note: required for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` to implement `Iterator`
39-
40-
error: aborting due to 3 previous errors
30+
error: aborting due to 2 previous errors
4131

4232
For more information about this error, try `rustc --explain E0271`.

0 commit comments

Comments
 (0)