Skip to content

Commit

Permalink
Rollup merge of rust-lang#82066 - matthewjasper:trait-ref-fix, r=jack…
Browse files Browse the repository at this point in the history
…h726

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```
  • Loading branch information
Dylan-DPC committed Feb 18, 2021
2 parents 945dbdd + eeb82e4 commit c53cc39
Show file tree
Hide file tree
Showing 34 changed files with 542 additions and 239 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,7 @@ impl<'a> State<'a> {

pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
self.print_ident(constraint.ident);
constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false));
self.s.space();
match &constraint.kind {
ast::AssocTyConstraintKind::Equality { ty } => {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ language_item_table! {

Deref, sym::deref, deref_trait, Target::Trait;
DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait;
DerefTarget, sym::deref_target, deref_target, Target::AssocTy;
Receiver, sym::receiver, receiver_trait, Target::Trait;

Fn, kw::Fn, fn_trait, Target::Trait;
Expand Down
25 changes: 24 additions & 1 deletion compiler/rustc_infer/src/infer/at.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {

pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
fn to_trace(
tcx: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
Expand Down Expand Up @@ -178,7 +179,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
where
T: ToTrace<'tcx>,
{
let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b);
let trace = ToTrace::to_trace(self.infcx.tcx, self.cause, a_is_expected, a, b);
Trace { at: self, trace, a_is_expected }
}
}
Expand Down Expand Up @@ -251,6 +252,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {

impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
fn to_trace(
_: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
Expand All @@ -262,6 +264,7 @@ impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {

impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
fn to_trace(
_: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
Expand All @@ -273,6 +276,7 @@ impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {

impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> {
fn to_trace(
_: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
Expand All @@ -284,6 +288,7 @@ impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> {

impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
fn to_trace(
_: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
Expand All @@ -298,6 +303,7 @@ impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {

impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
fn to_trace(
_: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
Expand All @@ -309,3 +315,20 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
}
}
}

impl<'tcx> ToTrace<'tcx> for ty::ProjectionTy<'tcx> {
fn to_trace(
tcx: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
b: Self,
) -> TypeTrace<'tcx> {
let a_ty = tcx.mk_projection(a.item_def_id, a.substs);
let b_ty = tcx.mk_projection(b.item_def_id, b.substs);
TypeTrace {
cause: cause.clone(),
values: Types(ExpectedFound::new(a_is_expected, a_ty, b_ty)),
}
}
}
40 changes: 34 additions & 6 deletions compiler/rustc_middle/src/ty/error.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::traits::{ObligationCause, ObligationCauseCode};
use crate::ty::diagnostics::suggest_constraining_type_param;
use crate::ty::print::{FmtPrinter, Printer};
use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
use rustc_errors::{pluralize, DiagnosticBuilder};
Expand Down Expand Up @@ -405,14 +406,22 @@ impl<'tcx> TyCtxt<'tcx> {
{
// Synthesize the associated type restriction `Add<Output = Expected>`.
// FIXME: extract this logic for use in other diagnostics.
let trait_ref = proj.trait_ref(self);
let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(self);
let path =
self.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs);
let item_name = self.item_name(proj.item_def_id);
let item_args = self.format_generic_args(assoc_substs);

let path = if path.ends_with('>') {
format!("{}, {} = {}>", &path[..path.len() - 1], item_name, p)
format!(
"{}, {}{} = {}>",
&path[..path.len() - 1],
item_name,
item_args,
p
)
} else {
format!("{}<{} = {}>", path, item_name, p)
format!("{}<{}{} = {}>", path, item_name, item_args, p)
};
note = !suggest_constraining_type_param(
self,
Expand Down Expand Up @@ -561,7 +570,7 @@ impl<T> Trait<T> for X {
ty: Ty<'tcx>,
) -> bool {
let assoc = self.associated_item(proj_ty.item_def_id);
let trait_ref = proj_ty.trait_ref(self);
let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
if let Some(item) = self.hir().get_if_local(body_owner_def_id) {
if let Some(hir_generics) = item.generics() {
// Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
Expand Down Expand Up @@ -595,6 +604,7 @@ impl<T> Trait<T> for X {
&trait_ref,
pred.bounds,
&assoc,
assoc_substs,
ty,
msg,
) {
Expand All @@ -612,6 +622,7 @@ impl<T> Trait<T> for X {
&trait_ref,
param.bounds,
&assoc,
assoc_substs,
ty,
msg,
);
Expand Down Expand Up @@ -697,6 +708,7 @@ impl<T> Trait<T> for X {
db,
self.def_span(def_id),
&assoc,
proj_ty.trait_ref_and_own_substs(self).1,
values.found,
&msg,
) {
Expand Down Expand Up @@ -861,6 +873,7 @@ fn foo(&self) -> Self::T { String::new() }
trait_ref: &ty::TraitRef<'tcx>,
bounds: hir::GenericBounds<'_>,
assoc: &ty::AssocItem,
assoc_substs: &[ty::GenericArg<'tcx>],
ty: Ty<'tcx>,
msg: &str,
) -> bool {
Expand All @@ -870,7 +883,12 @@ fn foo(&self) -> Self::T { String::new() }
// Relate the type param against `T` in `<A as T>::Foo`.
ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)
&& self.constrain_associated_type_structured_suggestion(
db, ptr.span, assoc, ty, msg,
db,
ptr.span,
assoc,
assoc_substs,
ty,
msg,
)
}
_ => false,
Expand All @@ -884,6 +902,7 @@ fn foo(&self) -> Self::T { String::new() }
db: &mut DiagnosticBuilder<'_>,
span: Span,
assoc: &ty::AssocItem,
assoc_substs: &[ty::GenericArg<'tcx>],
ty: Ty<'tcx>,
msg: &str,
) -> bool {
Expand All @@ -895,11 +914,20 @@ fn foo(&self) -> Self::T { String::new() }
let span = Span::new(pos, pos, span.ctxt());
(span, format!(", {} = {}", assoc.ident, ty))
} else {
(span.shrink_to_hi(), format!("<{} = {}>", assoc.ident, ty))
let item_args = self.format_generic_args(assoc_substs);
(span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident, item_args, ty))
};
db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
return true;
}
false
}

fn format_generic_args(self, args: &[ty::GenericArg<'tcx>]) -> String {
let mut item_args = String::new();
FmtPrinter::new(self, &mut item_args, hir::def::Namespace::TypeNS)
.path_generic_args(Ok, args)
.expect("could not write to `String`.");
item_args
}
}
16 changes: 15 additions & 1 deletion compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1289,8 +1289,22 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
self.skip_binder().projection_ty.item_def_id
}

/// Returns the `DefId` of the trait of the associated item being projected.
#[inline]
pub fn to_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
self.skip_binder().projection_ty.trait_def_id(tcx)
}

#[inline]
pub fn projection_self_ty(&self) -> Binder<Ty<'tcx>> {
self.map_bound(|predicate| predicate.projection_ty.self_ty())
}

/// Get the [PolyTraitRef] required for this projection to be well formed.
/// Note that for generic associated types the predicates of the associated
/// type also need to be checked.
#[inline]
pub fn required_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
// Note: unlike with `TraitRef::to_poly_trait_ref()`,
// `self.0.trait_ref` is permitted to have escaping regions.
// This is because here `self` has a `Binder` and so does our
Expand Down
70 changes: 41 additions & 29 deletions compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_index::vec::Idx;
use rustc_macros::HashStable;
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::symbol::{kw, Symbol};
use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi;
use std::borrow::Cow;
Expand Down Expand Up @@ -1112,36 +1112,35 @@ pub struct ProjectionTy<'tcx> {
}

impl<'tcx> ProjectionTy<'tcx> {
/// Construct a `ProjectionTy` by searching the trait from `trait_ref` for the
/// associated item named `item_name`.
pub fn from_ref_and_name(
tcx: TyCtxt<'_>,
trait_ref: ty::TraitRef<'tcx>,
item_name: Ident,
) -> ProjectionTy<'tcx> {
let item_def_id = tcx
.associated_items(trait_ref.def_id)
.find_by_name_and_kind(tcx, item_name, ty::AssocKind::Type, trait_ref.def_id)
.unwrap()
.def_id;
pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
tcx.associated_item(self.item_def_id).container.id()
}

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

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

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

pub fn with_self_ty(
Expand All @@ -1517,6 +1515,20 @@ impl<'tcx> ExistentialProjection<'tcx> {
ty: self.ty,
}
}

pub fn erase_self_ty(
tcx: TyCtxt<'tcx>,
projection_predicate: ty::ProjectionPredicate<'tcx>,
) -> Self {
// Assert there is a Self.
projection_predicate.projection_ty.substs.type_at(0);

Self {
item_def_id: projection_predicate.projection_ty.item_def_id,
substs: tcx.intern_substs(&projection_predicate.projection_ty.substs[1..]),
ty: projection_predicate.ty,
}
}
}

impl<'tcx> PolyExistentialProjection<'tcx> {
Expand Down
Loading

0 comments on commit c53cc39

Please sign in to comment.