Skip to content

Commit 66211f6

Browse files
authored
Rollup merge of #82066 - matthewjasper:trait-ref-fix, r=jackh726
Ensure valid TraitRefs are created for GATs This fixes `ProjectionTy::trait_ref` to use the correct substs. Places that need all of the substs have been updated to not use `trait_ref`. r? ````@jackh726````
2 parents 55ab2e3 + eeb82e4 commit 66211f6

34 files changed

+542
-239
lines changed

compiler/rustc_ast_pretty/src/pprust/state.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -914,6 +914,7 @@ impl<'a> State<'a> {
914914

915915
pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
916916
self.print_ident(constraint.ident);
917+
constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false));
917918
self.s.space();
918919
match &constraint.kind {
919920
ast::AssocTyConstraintKind::Equality { ty } => {

compiler/rustc_hir/src/lang_items.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ language_item_table! {
242242

243243
Deref, sym::deref, deref_trait, Target::Trait;
244244
DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait;
245+
DerefTarget, sym::deref_target, deref_target, Target::AssocTy;
245246
Receiver, sym::receiver, receiver_trait, Target::Trait;
246247

247248
Fn, kw::Fn, fn_trait, Target::Trait;

compiler/rustc_infer/src/infer/at.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
5555

5656
pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
5757
fn to_trace(
58+
tcx: TyCtxt<'tcx>,
5859
cause: &ObligationCause<'tcx>,
5960
a_is_expected: bool,
6061
a: Self,
@@ -178,7 +179,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
178179
where
179180
T: ToTrace<'tcx>,
180181
{
181-
let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b);
182+
let trace = ToTrace::to_trace(self.infcx.tcx, self.cause, a_is_expected, a, b);
182183
Trace { at: self, trace, a_is_expected }
183184
}
184185
}
@@ -251,6 +252,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
251252

252253
impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
253254
fn to_trace(
255+
_: TyCtxt<'tcx>,
254256
cause: &ObligationCause<'tcx>,
255257
a_is_expected: bool,
256258
a: Self,
@@ -262,6 +264,7 @@ impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
262264

263265
impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
264266
fn to_trace(
267+
_: TyCtxt<'tcx>,
265268
cause: &ObligationCause<'tcx>,
266269
a_is_expected: bool,
267270
a: Self,
@@ -273,6 +276,7 @@ impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
273276

274277
impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> {
275278
fn to_trace(
279+
_: TyCtxt<'tcx>,
276280
cause: &ObligationCause<'tcx>,
277281
a_is_expected: bool,
278282
a: Self,
@@ -284,6 +288,7 @@ impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> {
284288

285289
impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
286290
fn to_trace(
291+
_: TyCtxt<'tcx>,
287292
cause: &ObligationCause<'tcx>,
288293
a_is_expected: bool,
289294
a: Self,
@@ -298,6 +303,7 @@ impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
298303

299304
impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
300305
fn to_trace(
306+
_: TyCtxt<'tcx>,
301307
cause: &ObligationCause<'tcx>,
302308
a_is_expected: bool,
303309
a: Self,
@@ -309,3 +315,20 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
309315
}
310316
}
311317
}
318+
319+
impl<'tcx> ToTrace<'tcx> for ty::ProjectionTy<'tcx> {
320+
fn to_trace(
321+
tcx: TyCtxt<'tcx>,
322+
cause: &ObligationCause<'tcx>,
323+
a_is_expected: bool,
324+
a: Self,
325+
b: Self,
326+
) -> TypeTrace<'tcx> {
327+
let a_ty = tcx.mk_projection(a.item_def_id, a.substs);
328+
let b_ty = tcx.mk_projection(b.item_def_id, b.substs);
329+
TypeTrace {
330+
cause: cause.clone(),
331+
values: Types(ExpectedFound::new(a_is_expected, a_ty, b_ty)),
332+
}
333+
}
334+
}

compiler/rustc_middle/src/ty/error.rs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::traits::{ObligationCause, ObligationCauseCode};
22
use crate::ty::diagnostics::suggest_constraining_type_param;
3+
use crate::ty::print::{FmtPrinter, Printer};
34
use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
45
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
56
use rustc_errors::{pluralize, DiagnosticBuilder};
@@ -405,14 +406,22 @@ impl<'tcx> TyCtxt<'tcx> {
405406
{
406407
// Synthesize the associated type restriction `Add<Output = Expected>`.
407408
// FIXME: extract this logic for use in other diagnostics.
408-
let trait_ref = proj.trait_ref(self);
409+
let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(self);
409410
let path =
410411
self.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs);
411412
let item_name = self.item_name(proj.item_def_id);
413+
let item_args = self.format_generic_args(assoc_substs);
414+
412415
let path = if path.ends_with('>') {
413-
format!("{}, {} = {}>", &path[..path.len() - 1], item_name, p)
416+
format!(
417+
"{}, {}{} = {}>",
418+
&path[..path.len() - 1],
419+
item_name,
420+
item_args,
421+
p
422+
)
414423
} else {
415-
format!("{}<{} = {}>", path, item_name, p)
424+
format!("{}<{}{} = {}>", path, item_name, item_args, p)
416425
};
417426
note = !suggest_constraining_type_param(
418427
self,
@@ -561,7 +570,7 @@ impl<T> Trait<T> for X {
561570
ty: Ty<'tcx>,
562571
) -> bool {
563572
let assoc = self.associated_item(proj_ty.item_def_id);
564-
let trait_ref = proj_ty.trait_ref(self);
573+
let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
565574
if let Some(item) = self.hir().get_if_local(body_owner_def_id) {
566575
if let Some(hir_generics) = item.generics() {
567576
// Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
@@ -595,6 +604,7 @@ impl<T> Trait<T> for X {
595604
&trait_ref,
596605
pred.bounds,
597606
&assoc,
607+
assoc_substs,
598608
ty,
599609
msg,
600610
) {
@@ -612,6 +622,7 @@ impl<T> Trait<T> for X {
612622
&trait_ref,
613623
param.bounds,
614624
&assoc,
625+
assoc_substs,
615626
ty,
616627
msg,
617628
);
@@ -697,6 +708,7 @@ impl<T> Trait<T> for X {
697708
db,
698709
self.def_span(def_id),
699710
&assoc,
711+
proj_ty.trait_ref_and_own_substs(self).1,
700712
values.found,
701713
&msg,
702714
) {
@@ -861,6 +873,7 @@ fn foo(&self) -> Self::T { String::new() }
861873
trait_ref: &ty::TraitRef<'tcx>,
862874
bounds: hir::GenericBounds<'_>,
863875
assoc: &ty::AssocItem,
876+
assoc_substs: &[ty::GenericArg<'tcx>],
864877
ty: Ty<'tcx>,
865878
msg: &str,
866879
) -> bool {
@@ -870,7 +883,12 @@ fn foo(&self) -> Self::T { String::new() }
870883
// Relate the type param against `T` in `<A as T>::Foo`.
871884
ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)
872885
&& self.constrain_associated_type_structured_suggestion(
873-
db, ptr.span, assoc, ty, msg,
886+
db,
887+
ptr.span,
888+
assoc,
889+
assoc_substs,
890+
ty,
891+
msg,
874892
)
875893
}
876894
_ => false,
@@ -884,6 +902,7 @@ fn foo(&self) -> Self::T { String::new() }
884902
db: &mut DiagnosticBuilder<'_>,
885903
span: Span,
886904
assoc: &ty::AssocItem,
905+
assoc_substs: &[ty::GenericArg<'tcx>],
887906
ty: Ty<'tcx>,
888907
msg: &str,
889908
) -> bool {
@@ -895,11 +914,20 @@ fn foo(&self) -> Self::T { String::new() }
895914
let span = Span::new(pos, pos, span.ctxt());
896915
(span, format!(", {} = {}", assoc.ident, ty))
897916
} else {
898-
(span.shrink_to_hi(), format!("<{} = {}>", assoc.ident, ty))
917+
let item_args = self.format_generic_args(assoc_substs);
918+
(span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident, item_args, ty))
899919
};
900920
db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
901921
return true;
902922
}
903923
false
904924
}
925+
926+
fn format_generic_args(self, args: &[ty::GenericArg<'tcx>]) -> String {
927+
let mut item_args = String::new();
928+
FmtPrinter::new(self, &mut item_args, hir::def::Namespace::TypeNS)
929+
.path_generic_args(Ok, args)
930+
.expect("could not write to `String`.");
931+
item_args
932+
}
905933
}

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1289,8 +1289,22 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
12891289
self.skip_binder().projection_ty.item_def_id
12901290
}
12911291

1292+
/// Returns the `DefId` of the trait of the associated item being projected.
12921293
#[inline]
1293-
pub fn to_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
1294+
pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
1295+
self.skip_binder().projection_ty.trait_def_id(tcx)
1296+
}
1297+
1298+
#[inline]
1299+
pub fn projection_self_ty(&self) -> Binder<Ty<'tcx>> {
1300+
self.map_bound(|predicate| predicate.projection_ty.self_ty())
1301+
}
1302+
1303+
/// Get the [PolyTraitRef] required for this projection to be well formed.
1304+
/// Note that for generic associated types the predicates of the associated
1305+
/// type also need to be checked.
1306+
#[inline]
1307+
pub fn required_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
12941308
// Note: unlike with `TraitRef::to_poly_trait_ref()`,
12951309
// `self.0.trait_ref` is permitted to have escaping regions.
12961310
// This is because here `self` has a `Binder` and so does our

compiler/rustc_middle/src/ty/sty.rs

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_hir as hir;
1717
use rustc_hir::def_id::DefId;
1818
use rustc_index::vec::Idx;
1919
use rustc_macros::HashStable;
20-
use rustc_span::symbol::{kw, Ident, Symbol};
20+
use rustc_span::symbol::{kw, Symbol};
2121
use rustc_target::abi::VariantIdx;
2222
use rustc_target::spec::abi;
2323
use std::borrow::Cow;
@@ -1112,36 +1112,35 @@ pub struct ProjectionTy<'tcx> {
11121112
}
11131113

11141114
impl<'tcx> ProjectionTy<'tcx> {
1115-
/// Construct a `ProjectionTy` by searching the trait from `trait_ref` for the
1116-
/// associated item named `item_name`.
1117-
pub fn from_ref_and_name(
1118-
tcx: TyCtxt<'_>,
1119-
trait_ref: ty::TraitRef<'tcx>,
1120-
item_name: Ident,
1121-
) -> ProjectionTy<'tcx> {
1122-
let item_def_id = tcx
1123-
.associated_items(trait_ref.def_id)
1124-
.find_by_name_and_kind(tcx, item_name, ty::AssocKind::Type, trait_ref.def_id)
1125-
.unwrap()
1126-
.def_id;
1115+
pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
1116+
tcx.associated_item(self.item_def_id).container.id()
1117+
}
11271118

1128-
ProjectionTy { substs: trait_ref.substs, item_def_id }
1119+
/// Extracts the underlying trait reference and own substs from this projection.
1120+
/// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
1121+
/// then this function would return a `T: Iterator` trait reference and `['a]` as the own substs
1122+
pub fn trait_ref_and_own_substs(
1123+
&self,
1124+
tcx: TyCtxt<'tcx>,
1125+
) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
1126+
let def_id = tcx.associated_item(self.item_def_id).container.id();
1127+
let trait_generics = tcx.generics_of(def_id);
1128+
(
1129+
ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, trait_generics) },
1130+
&self.substs[trait_generics.count()..],
1131+
)
11291132
}
11301133

11311134
/// Extracts the underlying trait reference from this projection.
11321135
/// For example, if this is a projection of `<T as Iterator>::Item`,
11331136
/// then this function would return a `T: Iterator` trait reference.
1137+
///
1138+
/// WARNING: This will drop the substs for generic associated types
1139+
/// consider calling [Self::trait_ref_and_own_substs] to get those
1140+
/// as well.
11341141
pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
1135-
// FIXME: This method probably shouldn't exist at all, since it's not
1136-
// clear what this method really intends to do. Be careful when
1137-
// using this method since the resulting TraitRef additionally
1138-
// contains the substs for the assoc_item, which strictly speaking
1139-
// is not correct
1140-
let def_id = tcx.associated_item(self.item_def_id).container.id();
1141-
// Include substitutions for generic arguments of associated types
1142-
let assoc_item = tcx.associated_item(self.item_def_id);
1143-
let substs_assoc_item = self.substs.truncate_to(tcx, tcx.generics_of(assoc_item.def_id));
1144-
ty::TraitRef { def_id, substs: substs_assoc_item }
1142+
let def_id = self.trait_def_id(tcx);
1143+
ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, tcx.generics_of(def_id)) }
11451144
}
11461145

11471146
pub fn self_ty(&self) -> Ty<'tcx> {
@@ -1493,12 +1492,11 @@ impl<'tcx> ExistentialProjection<'tcx> {
14931492
/// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
14941493
/// then this function would return a `exists T. T: Iterator` existential trait
14951494
/// reference.
1496-
pub fn trait_ref(&self, tcx: TyCtxt<'_>) -> ty::ExistentialTraitRef<'tcx> {
1497-
// FIXME(generic_associated_types): substs is the substs of the
1498-
// associated type, which should be truncated to get the correct substs
1499-
// for the trait.
1495+
pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> {
15001496
let def_id = tcx.associated_item(self.item_def_id).container.id();
1501-
ty::ExistentialTraitRef { def_id, substs: self.substs }
1497+
let subst_count = tcx.generics_of(def_id).count() - 1;
1498+
let substs = tcx.intern_substs(&self.substs[..subst_count]);
1499+
ty::ExistentialTraitRef { def_id, substs }
15021500
}
15031501

15041502
pub fn with_self_ty(
@@ -1517,6 +1515,20 @@ impl<'tcx> ExistentialProjection<'tcx> {
15171515
ty: self.ty,
15181516
}
15191517
}
1518+
1519+
pub fn erase_self_ty(
1520+
tcx: TyCtxt<'tcx>,
1521+
projection_predicate: ty::ProjectionPredicate<'tcx>,
1522+
) -> Self {
1523+
// Assert there is a Self.
1524+
projection_predicate.projection_ty.substs.type_at(0);
1525+
1526+
Self {
1527+
item_def_id: projection_predicate.projection_ty.item_def_id,
1528+
substs: tcx.intern_substs(&projection_predicate.projection_ty.substs[1..]),
1529+
ty: projection_predicate.ty,
1530+
}
1531+
}
15201532
}
15211533

15221534
impl<'tcx> PolyExistentialProjection<'tcx> {

0 commit comments

Comments
 (0)