diff options
| author | jackh726 <jack.huey@umassmed.edu> | 2021-07-21 10:23:43 -0400 |
|---|---|---|
| committer | jackh726 <jack.huey@umassmed.edu> | 2021-07-21 10:23:43 -0400 |
| commit | 62f85149139ccf10391f053663c772d9811f2536 (patch) | |
| tree | 20ee52abd2a81369f82425435e27cf0e354a6f08 | |
| parent | 3d464947d421744017b9709215f14911ea25947e (diff) | |
| download | rust-issue-85533.tar.gz | |
WIP find constrained generics of type aliasissue-85533
| -rw-r--r-- | compiler/rustc_driver/src/lib.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_metadata/src/rmeta/decoder.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_metadata/src/rmeta/encoder.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_metadata/src/rmeta/mod.rs | 26 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/hir/mod.rs | 71 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/query/mod.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/trait_def.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/late/lifetimes.rs | 44 | ||||
| -rw-r--r-- | compiler/rustc_ty_utils/src/ty.rs | 34 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/astconv/mod.rs | 2 | ||||
| -rw-r--r-- | src/test/ui/generic-associated-types/issue-85533.rs | 14 | ||||
| -rw-r--r-- | src/test/ui/issues/issue-47511.rs | 27 |
13 files changed, 215 insertions, 28 deletions
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 326fefa59ab..81ee9b52575 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -1293,9 +1293,9 @@ pub fn init_env_logger(env: &str) { .with_indent_lines(true) .with_ansi(color_logs) .with_targets(true) - .with_wraparound(10) - .with_verbose_exit(true) - .with_verbose_entry(true) + //.with_wraparound(10) + //.with_verbose_exit(true) + //.with_verbose_entry(true) .with_indent_amount(2); #[cfg(parallel_compiler)] let layer = layer.with_thread_ids(true).with_thread_names(true); diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 8bdd4313de4..f59cce0302b 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -962,6 +962,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.get_impl_data(id).constness } + fn constrained_generics_of_ty_alias(&self, id: DefIndex) -> Vec<usize> { + match self.kind(id) { + EntryKind::Type(data) => data.decode(self).constrained_subst_indices, + _ => bug!(), + } + } + fn get_coerce_unsized_info(&self, id: DefIndex) -> Option<ty::adjustment::CoerceUnsizedInfo> { self.get_impl_data(id).coerce_unsized_info } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 41839c58021..e90375bc494 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -168,6 +168,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, symbol_mangling_version => { cdata.root.symbol_mangling_version } impl_defaultness => { cdata.get_impl_defaultness(def_id.index) } impl_constness => { cdata.get_impl_constness(def_id.index) } + constrained_generics_of_ty_alias => { cdata.constrained_generics_of_ty_alias(def_id.index) } reachable_non_generics => { let reachable_non_generics = tcx .exported_symbols(cdata.cnum) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index a4913a32e81..282888973b9 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1378,7 +1378,10 @@ impl EncodeContext<'a, 'tcx> { } hir::ItemKind::ForeignMod { .. } => EntryKind::ForeignMod, hir::ItemKind::GlobalAsm(..) => EntryKind::GlobalAsm, - hir::ItemKind::TyAlias(..) => EntryKind::Type, + hir::ItemKind::TyAlias(..) => { + let constrained_subst_indices = self.tcx.constrained_generics_of_ty_alias(def_id); + EntryKind::Type(self.lazy(TypeData { constrained_subst_indices })) + } hir::ItemKind::OpaqueTy(..) => { self.encode_explicit_item_bounds(def_id); EntryKind::OpaqueTy diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index a487753f462..d7ea19df0f2 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -109,6 +109,7 @@ impl<T> LazyMeta for [T] { #[must_use] // FIXME(#59875) the `Meta` parameter only exists to dodge // invariance wrt `T` (coming from the `meta: T::Meta` field). +#[derive(Debug)] struct Lazy<T, Meta = <T as LazyMeta>::Meta> where T: ?Sized + LazyMeta<Meta = Meta>, @@ -317,7 +318,7 @@ define_tables! { proc_macro_quoted_spans: Table<usize, Lazy<Span>>, } -#[derive(Copy, Clone, MetadataEncodable, MetadataDecodable)] +#[derive(Copy, Clone, Debug, MetadataEncodable, MetadataDecodable)] enum EntryKind { AnonConst(mir::ConstQualifs, Lazy<RenderedConst>), Const(mir::ConstQualifs, Lazy<RenderedConst>), @@ -328,7 +329,7 @@ enum EntryKind { ForeignMod, ForeignType, GlobalAsm, - Type, + Type(Lazy<TypeData>), TypeParam, ConstParam, OpaqueTy, @@ -354,23 +355,23 @@ enum EntryKind { /// Contains a constant which has been rendered to a String. /// Used by rustdoc. -#[derive(Encodable, Decodable)] +#[derive(Debug, Encodable, Decodable)] struct RenderedConst(String); -#[derive(MetadataEncodable, MetadataDecodable)] +#[derive(Debug, MetadataEncodable, MetadataDecodable)] struct ModData { reexports: Lazy<[Export<hir::HirId>]>, expansion: ExpnId, } -#[derive(MetadataEncodable, MetadataDecodable)] +#[derive(Debug, MetadataEncodable, MetadataDecodable)] struct FnData { asyncness: hir::IsAsync, constness: hir::Constness, param_names: Lazy<[Ident]>, } -#[derive(TyEncodable, TyDecodable)] +#[derive(Debug, TyEncodable, TyDecodable)] struct VariantData { ctor_kind: CtorKind, discr: ty::VariantDiscr, @@ -379,7 +380,7 @@ struct VariantData { is_non_exhaustive: bool, } -#[derive(TyEncodable, TyDecodable)] +#[derive(Debug, TyEncodable, TyDecodable)] struct TraitData { unsafety: hir::Unsafety, paren_sugar: bool, @@ -389,7 +390,7 @@ struct TraitData { specialization_kind: ty::trait_def::TraitSpecializationKind, } -#[derive(TyEncodable, TyDecodable)] +#[derive(Debug, TyEncodable, TyDecodable)] struct ImplData { polarity: ty::ImplPolarity, constness: hir::Constness, @@ -401,10 +402,15 @@ struct ImplData { coerce_unsized_info: Option<ty::adjustment::CoerceUnsizedInfo>, } +#[derive(Debug, TyEncodable, TyDecodable)] +struct TypeData { + constrained_subst_indices: Vec<usize>, +} + /// Describes whether the container of an associated item /// is a trait or an impl and whether, in a trait, it has /// a default, or an in impl, whether it's marked "default". -#[derive(Copy, Clone, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable)] enum AssocContainer { TraitRequired, TraitWithDefault, @@ -436,7 +442,7 @@ impl AssocContainer { } } -#[derive(MetadataEncodable, MetadataDecodable)] +#[derive(Debug, MetadataEncodable, MetadataDecodable)] struct AssocFnData { fn_data: FnData, container: AssocContainer, diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 3026bf8274d..308bd674051 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -9,12 +9,17 @@ pub mod place; use crate::ich::StableHashingContext; use crate::ty::query::Providers; use crate::ty::TyCtxt; +use hir::def::{DefKind, Res}; +use hir::def_id::DefId; +use hir::intravisit::Visitor; use rustc_ast::Attribute; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::stable_set::FxHashSet; use rustc_hir::def_id::LocalDefId; use rustc_hir::*; +use rustc_hir as hir; use rustc_index::vec::{Idx, IndexVec}; use rustc_span::DUMMY_SP; use std::collections::BTreeMap; @@ -118,6 +123,72 @@ impl<'tcx> AttributeMap<'tcx> { } } +pub struct ConstrainedCollector<'tcx> { + pub tcx: TyCtxt<'tcx>, + pub regions: FxHashSet<hir::LifetimeName>, + pub types: FxHashSet<DefId>, +} + +impl<'v, 'tcx> Visitor<'v> for ConstrainedCollector<'tcx> { + type Map = intravisit::ErasedMap<'v>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> { + intravisit::NestedVisitorMap::None + } + + fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { + debug!(?ty); + match ty.kind { + hir::TyKind::Path( + hir::QPath::Resolved(Some(_), _) | hir::QPath::TypeRelative(..), + ) => { + // ignore lifetimes appearing in associated type + // projections, as they are not *constrained* + // (defined above) + } + + hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => { + // consider only the lifetimes on the final + // segment; I am not sure it's even currently + // valid to have them elsewhere, but even if it + // is, those would be potentially inputs to + // projections + if let Some(last_segment) = path.segments.last() { + match path.res { + Res::Def(DefKind::TyAlias, def_id) => { + let constrained = self.tcx.constrained_generics_of_ty_alias(def_id); + if let Some(args) = last_segment.args { + let args = args.args; + constrained.into_iter().take_while(|i| *i < args.len()).for_each(|i| { + let param = &args[i]; + match param { + hir::GenericArg::Lifetime(lt) => { + self.regions.insert(lt.name.normalize_to_macros_2_0()); + } + _ => {} + } + }); + } + } + Res::Def(DefKind::TyParam, def_id) => { + self.types.insert(def_id); + } + _ => self.visit_path_segment(path.span, last_segment), + } + } + } + + _ => { + intravisit::walk_ty(self, ty); + } + } + } + + fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { + self.regions.insert(lifetime_ref.name.normalize_to_macros_2_0()); + } +} + impl<'tcx> TyCtxt<'tcx> { #[inline(always)] pub fn hir(self) -> map::Map<'tcx> { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index cb99ae19ee7..27aab4d6893 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1150,6 +1150,10 @@ rustc_queries! { desc { |tcx| "looking up whether `{}` is a const impl", tcx.def_path_str(def_id) } } + query constrained_generics_of_ty_alias(def_id: DefId) -> Vec<usize> { + desc { "the set of generics that are constrained within a type alias" } + } + query check_item_well_formed(key: LocalDefId) -> () { desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) } } diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index ae86f51e6ac..60f7bce5cb4 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -50,7 +50,7 @@ pub struct TraitDef { /// Whether this trait is treated specially by the standard library /// specialization lint. -#[derive(HashStable, PartialEq, Clone, Copy, TyEncodable, TyDecodable)] +#[derive(Debug, HashStable, PartialEq, Clone, Copy, TyEncodable, TyDecodable)] pub enum TraitSpecializationKind { /// The default. Specializing on this trait is not allowed. None, diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index ca7cdc4caf5..0d851c0342e 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -2173,7 +2173,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { ) where F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>), { - insert_late_bound_lifetimes(self.map, decl, generics); + insert_late_bound_lifetimes(self.tcx, self.map, decl, generics); // Find the start of nested early scopes, e.g., in methods. let mut next_early_index = 0; @@ -3488,13 +3488,18 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { /// "Constrained" basically means that it appears in any type but /// not amongst the inputs to a projection. In other words, `<&'a /// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`. -#[tracing::instrument(level = "debug", skip(map))] -fn insert_late_bound_lifetimes( +#[tracing::instrument(level = "debug", skip(tcx, map))] +fn insert_late_bound_lifetimes<'tcx>( + tcx: TyCtxt<'tcx>, map: &mut NamedRegionMap, decl: &hir::FnDecl<'_>, generics: &hir::Generics<'_>, ) { - let mut constrained_by_input = ConstrainedCollector::default(); + let mut constrained_by_input = rustc_middle::hir::ConstrainedCollector { + tcx, + regions: FxHashSet::default(), + types: FxHashSet::default(), + }; for arg_ty in decl.inputs { constrained_by_input.visit_ty(arg_ty); } @@ -3557,12 +3562,14 @@ fn insert_late_bound_lifetimes( return; - #[derive(Default)] - struct ConstrainedCollector { +/* + struct ConstrainedCollector<'tcx> { + tcx: TyCtxt<'tcx>, regions: FxHashSet<hir::LifetimeName>, + types: FxHashSet<DefId>, } - impl<'v> Visitor<'v> for ConstrainedCollector { + impl<'v, 'tcx> Visitor<'v> for ConstrainedCollector<'tcx> { type Map = intravisit::ErasedMap<'v>; fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { @@ -3570,6 +3577,7 @@ fn insert_late_bound_lifetimes( } fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { + debug!(?ty); match ty.kind { hir::TyKind::Path( hir::QPath::Resolved(Some(_), _) | hir::QPath::TypeRelative(..), @@ -3586,7 +3594,25 @@ fn insert_late_bound_lifetimes( // is, those would be potentially inputs to // projections if let Some(last_segment) = path.segments.last() { - self.visit_path_segment(path.span, last_segment); + match path.res { + Res::Def(DefKind::TyAlias, def_id) => { + let constrained = self.tcx.constrained_generics_of_ty_alias(def_id); + if let Some(args) = last_segment.args { + let args = args.args; + constrained.into_iter().for_each(|i| { + let param = &args[i]; + match param { + hir::GenericArg::Lifetime(lt) => { + self.regions.insert(lt.name.normalize_to_macros_2_0()); + } + _ => {} + } + }); + } + } + Res::Def(DefKind::TyParam, def_id) => self.types.insert(def_id), + _ => self.visit_path_segment(path.span, last_segment), + } } } @@ -3600,7 +3626,7 @@ fn insert_late_bound_lifetimes( self.regions.insert(lifetime_ref.name.normalize_to_macros_2_0()); } } - +*/ #[derive(Default)] struct AllCollector { regions: FxHashSet<hir::LifetimeName>, diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index b0d644ae028..39a2f0f24c2 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -1,6 +1,8 @@ use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::stable_set::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::intravisit::Visitor; use rustc_middle::hir::map as hir_map; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{ @@ -531,6 +533,37 @@ pub fn conservative_is_privately_uninhabited_raw<'tcx>( } } +pub fn constrained_generics_of_ty_alias<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<usize> { + let node = tcx.hir().get_if_local(def_id).unwrap(); + match node { + hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(ty, generics), .. }) => { + let mut collector = rustc_middle::hir::ConstrainedCollector { + tcx, + regions: FxHashSet::default(), + types: FxHashSet::default(), + }; + collector.visit_ty(ty); + debug!(?collector.regions, ?generics); + let collected_regions: FxHashSet<_> = collector + .regions + .iter() + .filter_map(|r| { + match r { + hir::LifetimeName::Param(hir::ParamName::Plain(found_ident)) => Some(found_ident.name), + _ => None, + } + }).collect(); + generics.params.iter().enumerate().filter_map(|(i, param)| { + match param.name { + hir::ParamName::Plain(ident) if collected_regions.contains(&ident.name) => Some(i), + _ => collector.types.contains(&tcx.hir().local_def_id(param.hir_id).to_def_id()).then(|| i), + } + }).collect() + } + _ => bug!("{:?}", node), + } +} + pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { asyncness, @@ -547,6 +580,7 @@ pub fn provide(providers: &mut ty::query::Providers) { impl_defaultness, impl_constness, conservative_is_privately_uninhabited: conservative_is_privately_uninhabited_raw, + constrained_generics_of_ty_alias, ..*providers }; } diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 2e42d65cce2..52b7a3b5abd 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2428,12 +2428,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Example: // for<'a> fn() -> &'a str <-- 'a is bad // for<'a> fn(&'a String) -> &'a str <-- 'a is ok + debug!(?bare_fn_ty); let inputs = bare_fn_ty.inputs(); let late_bound_in_args = tcx.collect_constrained_late_bound_regions(&inputs.map_bound(|i| i.to_owned())); let output = bare_fn_ty.output(); let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output); + debug!(?late_bound_in_args, ?late_bound_in_ret); self.validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| { struct_span_err!( tcx.sess, diff --git a/src/test/ui/generic-associated-types/issue-85533.rs b/src/test/ui/generic-associated-types/issue-85533.rs new file mode 100644 index 00000000000..70a7a35cace --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-85533.rs @@ -0,0 +1,14 @@ +// check-pass + +#![feature(generic_associated_types)] + +trait Trait { + type Assoc<'a>; +} + +type AssocAlias<'a, T> = <T as Trait>::Assoc<'a>; + +fn works<'a, T: Trait>(entity: T::Assoc<'a>) -> &'a i32 {&5} +fn fails<'a, T: Trait>(entity: AssocAlias<'a, T>) -> &'a i32 {&5} + +fn main() {} diff --git a/src/test/ui/issues/issue-47511.rs b/src/test/ui/issues/issue-47511.rs index 0f33b52577b..fe908aaecf9 100644 --- a/src/test/ui/issues/issue-47511.rs +++ b/src/test/ui/issues/issue-47511.rs @@ -2,14 +2,23 @@ // unconstrained in a return type, but only if they appear just once // in the input, as the input to a projection. +#![feature(no_core)] +#![no_core] + fn f(_: X) -> X { //~^ ERROR return type references an anonymous lifetime - unimplemented!() + //unimplemented!() + loop {} } fn g<'a>(_: X<'a>) -> X<'a> { - //~^ ERROR return type references lifetime `'a`, which is not constrained - unimplemented!() + //unimplemented!() + loop {} +} + +fn h<'a>(_: Y<'a, Foo<'a>>) -> X<'a> { + //unimplemented!() + loop {} } type X<'a> = <&'a () as Trait>::Value; @@ -22,4 +31,14 @@ impl<'a> Trait for &'a () { type Value = (); } -fn main() {} +type Y<'a, T> = (T, <&'a () as Trait>::Value); + +struct Foo<'a>(&'a ()); + +fn a<'a>(_: (Foo<'a>, ())) -> () {} +fn b<'a>(_: ((), ())) -> () {} + +fn main() { + let _a: for<'a> fn(Y<'a, ()>) -> X<'a> = a; + let _b: for<'a> fn(Y<'a, Foo<'a>>) -> X<'a> = b; +} |
