summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjackh726 <jack.huey@umassmed.edu>2021-07-21 10:23:43 -0400
committerjackh726 <jack.huey@umassmed.edu>2021-07-21 10:23:43 -0400
commit62f85149139ccf10391f053663c772d9811f2536 (patch)
tree20ee52abd2a81369f82425435e27cf0e354a6f08
parent3d464947d421744017b9709215f14911ea25947e (diff)
downloadrust-issue-85533.tar.gz
WIP find constrained generics of type aliasissue-85533
-rw-r--r--compiler/rustc_driver/src/lib.rs6
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs7
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs1
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs5
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs26
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs71
-rw-r--r--compiler/rustc_middle/src/query/mod.rs4
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs2
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs44
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs34
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs2
-rw-r--r--src/test/ui/generic-associated-types/issue-85533.rs14
-rw-r--r--src/test/ui/issues/issue-47511.rs27
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;
+}