Restrict concrete types to equivalent types
This commit is contained in:
parent
cf01b514c8
commit
6f83dcc192
25 changed files with 264 additions and 33 deletions
|
|
@ -233,6 +233,11 @@ impl_stable_hash_for!(struct ty::FnSig<'tcx> {
|
|||
abi
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(struct ty::ResolvedOpaqueTy<'tcx> {
|
||||
concrete_type,
|
||||
substs
|
||||
});
|
||||
|
||||
impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>> for ty::Binder<T>
|
||||
where T: HashStable<StableHashingContext<'a>>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ pub struct OpaqueTypeDecl<'tcx> {
|
|||
///
|
||||
/// winds up desugared to:
|
||||
///
|
||||
/// abstract type Foo<'x, T>: Trait<'x>
|
||||
/// abstract type Foo<'x, X>: Trait<'x>
|
||||
/// fn foo<'a, 'b, T>() -> Foo<'a, T>
|
||||
///
|
||||
/// then `substs` would be `['a, T]`.
|
||||
|
|
|
|||
|
|
@ -315,6 +315,17 @@ impl<'a, V> LocalTableInContextMut<'a, V> {
|
|||
}
|
||||
}
|
||||
|
||||
/// All information necessary to validate and reveal an `impl Trait` or `existential Type`
|
||||
#[derive(RustcEncodable, RustcDecodable, Debug)]
|
||||
pub struct ResolvedOpaqueTy<'tcx> {
|
||||
/// The revealed type as seen by this function.
|
||||
pub concrete_type: Ty<'tcx>,
|
||||
/// Generic parameters on the opaque type as passed by this function.
|
||||
/// For `existential type Foo<A, B>; fn foo<T, U>() -> Foo<T, U> { .. }` this is `[T, U]`, not
|
||||
/// `[A, B]`
|
||||
pub substs: &'tcx Substs<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable, Debug)]
|
||||
pub struct TypeckTables<'tcx> {
|
||||
/// The HirId::owner all ItemLocalIds in this table are relative to.
|
||||
|
|
@ -417,7 +428,7 @@ pub struct TypeckTables<'tcx> {
|
|||
|
||||
/// All the existential types that are restricted to concrete types
|
||||
/// by this function
|
||||
pub concrete_existential_types: FxHashMap<DefId, Ty<'tcx>>,
|
||||
pub concrete_existential_types: FxHashMap<DefId, ResolvedOpaqueTy<'tcx>>,
|
||||
|
||||
/// Given the closure ID this map provides the list of UpvarIDs used by it.
|
||||
/// The upvarID contains the HIR node ID and it also contains the full path
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ pub use self::context::{TyCtxt, FreeRegionInfo, GlobalArenas, AllArenas, tls, ke
|
|||
pub use self::context::{Lift, TypeckTables, CtxtInterners};
|
||||
pub use self::context::{
|
||||
UserTypeAnnotationIndex, UserType, CanonicalUserType,
|
||||
CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
|
||||
CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, ResolvedOpaqueTy,
|
||||
};
|
||||
|
||||
pub use self::instance::{Instance, InstanceDef};
|
||||
|
|
|
|||
|
|
@ -567,17 +567,23 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
let new = ty::ResolvedOpaqueTy {
|
||||
concrete_type: definition_ty,
|
||||
substs: self.tcx().lift_to_global(&opaque_defn.substs).unwrap(),
|
||||
};
|
||||
|
||||
let old = self.tables
|
||||
.concrete_existential_types
|
||||
.insert(def_id, definition_ty);
|
||||
.insert(def_id, new);
|
||||
if let Some(old) = old {
|
||||
if old != definition_ty {
|
||||
if old.concrete_type != definition_ty || old.substs != opaque_defn.substs {
|
||||
span_bug!(
|
||||
span,
|
||||
"visit_opaque_types tried to write \
|
||||
different types for the same existential type: {:?}, {:?}, {:?}",
|
||||
different types for the same existential type: {:?}, {:?}, {:?}, {:?}",
|
||||
def_id,
|
||||
definition_ty,
|
||||
opaque_defn,
|
||||
old,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,9 +23,10 @@ use middle::resolve_lifetime as rl;
|
|||
use middle::weak_lang_items;
|
||||
use rustc::mir::mono::Linkage;
|
||||
use rustc::ty::query::Providers;
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::subst::{Subst, Substs};
|
||||
use rustc::ty::util::Discr;
|
||||
use rustc::ty::util::IntTypeExt;
|
||||
use rustc::ty::subst::UnpackedKind;
|
||||
use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
|
||||
use rustc::ty::{ReprOptions, ToPredicate};
|
||||
use rustc::util::captures::Captures;
|
||||
|
|
@ -1193,7 +1194,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
|
|||
tcx.typeck_tables_of(owner)
|
||||
.concrete_existential_types
|
||||
.get(&def_id)
|
||||
.cloned()
|
||||
.map(|opaque| opaque.concrete_type)
|
||||
.unwrap_or_else(|| {
|
||||
// This can occur if some error in the
|
||||
// owner fn prevented us from populating
|
||||
|
|
@ -1325,7 +1326,13 @@ fn find_existential_constraints<'a, 'tcx>(
|
|||
struct ConstraintLocator<'a, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
def_id: DefId,
|
||||
found: Option<(Span, ty::Ty<'tcx>)>,
|
||||
// First found type span, actual type, mapping from the existential type's generic
|
||||
// parameters to the concrete type's generic parameters
|
||||
//
|
||||
// The mapping is an index for each use site of a generic parameter in the concrete type
|
||||
//
|
||||
// The indices index into the generic parameters on the existential type.
|
||||
found: Option<(Span, ty::Ty<'tcx>, Vec<usize>)>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ConstraintLocator<'a, 'tcx> {
|
||||
|
|
@ -1340,13 +1347,50 @@ fn find_existential_constraints<'a, 'tcx>(
|
|||
.tcx
|
||||
.typeck_tables_of(def_id)
|
||||
.concrete_existential_types
|
||||
.get(&self.def_id)
|
||||
.cloned();
|
||||
if let Some(ty) = ty {
|
||||
.get(&self.def_id);
|
||||
if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty {
|
||||
// FIXME(oli-obk): trace the actual span from inference to improve errors
|
||||
let span = self.tcx.def_span(def_id);
|
||||
if let Some((prev_span, prev_ty)) = self.found {
|
||||
let mut ty = ty.walk().fuse();
|
||||
// used to quickly look up the position of a generic parameter
|
||||
let mut index_map: FxHashMap<ty::ParamTy, usize> = FxHashMap::default();
|
||||
// skip binder is ok, since we only use this to find generic parameters and their
|
||||
// positions.
|
||||
for subst in substs.iter() {
|
||||
if let UnpackedKind::Type(ty) = subst.unpack() {
|
||||
if let ty::Param(p) = ty.sty {
|
||||
let idx = index_map.len();
|
||||
if index_map.insert(p, idx).is_some() {
|
||||
// there was already an entry for `p`, meaning a generic parameter
|
||||
// was used twice
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
&format!("defining existential type use restricts existential \
|
||||
type by using the generic parameter `{}` twice", p.name),
|
||||
);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
self.tcx.sess.delay_span_bug(
|
||||
span,
|
||||
&format!(
|
||||
"non-defining exist ty use in defining scope: {:?}, {:?}",
|
||||
concrete_type, substs,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// compute the index within the existential type for each generic parameter used in
|
||||
// the concrete type
|
||||
let indices = concrete_type
|
||||
.subst(self.tcx, substs)
|
||||
.walk()
|
||||
.filter_map(|t| match &t.sty {
|
||||
ty::Param(p) => Some(*index_map.get(p).unwrap()),
|
||||
_ => None,
|
||||
}).collect();
|
||||
if let Some((prev_span, prev_ty, ref prev_indices)) = self.found {
|
||||
let mut ty = concrete_type.walk().fuse();
|
||||
let mut prev_ty = prev_ty.walk().fuse();
|
||||
let iter_eq = (&mut ty).zip(&mut prev_ty).all(|(t, p)| match (&t.sty, &p.sty) {
|
||||
// type parameters are equal to any other type parameter for the purpose of
|
||||
|
|
@ -1359,13 +1403,21 @@ fn find_existential_constraints<'a, 'tcx>(
|
|||
// found different concrete types for the existential type
|
||||
let mut err = self.tcx.sess.struct_span_err(
|
||||
span,
|
||||
"defining existential type use differs from previous",
|
||||
"concrete type differs from previous defining existential type use",
|
||||
);
|
||||
err.span_note(prev_span, "previous use here");
|
||||
err.emit();
|
||||
} else if indices != *prev_indices {
|
||||
// found "same" concrete types, but the generic parameter order differs
|
||||
let mut err = self.tcx.sess.struct_span_err(
|
||||
span,
|
||||
"concrete type's generic parameters differ from previous defining use",
|
||||
);
|
||||
err.span_note(prev_span, "previous use here");
|
||||
err.emit();
|
||||
}
|
||||
} else {
|
||||
self.found = Some((span, ty));
|
||||
self.found = Some((span, concrete_type, indices));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1424,7 +1476,7 @@ fn find_existential_constraints<'a, 'tcx>(
|
|||
}
|
||||
|
||||
match locator.found {
|
||||
Some((_, ty)) => ty,
|
||||
Some((_, ty, _)) => ty,
|
||||
None => {
|
||||
let span = tcx.def_span(def_id);
|
||||
tcx.sess.span_err(span, "could not find defining uses");
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@ fn foo() -> Foo {
|
|||
""
|
||||
}
|
||||
|
||||
fn bar() -> Foo { //~ ERROR defining existential type use differs from previous
|
||||
fn bar() -> Foo { //~ ERROR concrete type differs from previous
|
||||
42i32
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
error: defining existential type use differs from previous
|
||||
error: concrete type differs from previous defining existential type use
|
||||
--> $DIR/different_defining_uses.rs:12:1
|
||||
|
|
||||
LL | / fn bar() -> Foo { //~ ERROR defining existential type use differs from previous
|
||||
LL | / fn bar() -> Foo { //~ ERROR concrete type differs from previous
|
||||
LL | | 42i32
|
||||
LL | | }
|
||||
| |_^
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ fn foo() -> Foo {
|
|||
""
|
||||
}
|
||||
|
||||
fn bar() -> Foo { //~ ERROR defining existential type use differs from previous
|
||||
fn bar() -> Foo { //~ ERROR concrete type differs from previous
|
||||
panic!()
|
||||
}
|
||||
|
||||
fn boo() -> Foo { //~ ERROR defining existential type use differs from previous
|
||||
fn boo() -> Foo { //~ ERROR concrete type differs from previous
|
||||
loop {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
error: defining existential type use differs from previous
|
||||
error: concrete type differs from previous defining existential type use
|
||||
--> $DIR/different_defining_uses_never_type.rs:12:1
|
||||
|
|
||||
LL | / fn bar() -> Foo { //~ ERROR defining existential type use differs from previous
|
||||
LL | / fn bar() -> Foo { //~ ERROR concrete type differs from previous
|
||||
LL | | panic!()
|
||||
LL | | }
|
||||
| |_^
|
||||
|
|
@ -14,10 +14,10 @@ LL | | ""
|
|||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: defining existential type use differs from previous
|
||||
error: concrete type differs from previous defining existential type use
|
||||
--> $DIR/different_defining_uses_never_type.rs:16:1
|
||||
|
|
||||
LL | / fn boo() -> Foo { //~ ERROR defining existential type use differs from previous
|
||||
LL | / fn boo() -> Foo { //~ ERROR concrete type differs from previous
|
||||
LL | | loop {}
|
||||
LL | | }
|
||||
| |_^
|
||||
|
|
|
|||
|
|
@ -8,6 +8,6 @@ fn my_iter<T>(t: T) -> MyIter<T> {
|
|||
std::iter::once(t)
|
||||
}
|
||||
|
||||
fn my_iter2<T>(t: T) -> MyIter<T> { //~ ERROR defining existential type use differs from previous
|
||||
fn my_iter2<T>(t: T) -> MyIter<T> { //~ ERROR concrete type differs from previous
|
||||
Some(t).into_iter()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
error: defining existential type use differs from previous
|
||||
error: concrete type differs from previous defining existential type use
|
||||
--> $DIR/generic_different_defining_uses.rs:11:1
|
||||
|
|
||||
LL | / fn my_iter2<T>(t: T) -> MyIter<T> { //~ ERROR defining existential type use differs from previous
|
||||
LL | / fn my_iter2<T>(t: T) -> MyIter<T> { //~ ERROR concrete type differs from previous
|
||||
LL | | Some(t).into_iter()
|
||||
LL | | }
|
||||
| |_^
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// compile-pass
|
||||
#![feature(existential_type)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
|
@ -7,7 +6,9 @@ fn main() {}
|
|||
|
||||
// test that unused generic parameters are ok
|
||||
existential type Two<T, U>: Debug;
|
||||
//~^ could not find defining uses
|
||||
|
||||
fn one<T: Debug>(t: T) -> Two<T, T> {
|
||||
//~^ ERROR defining existential type use restricts existential type
|
||||
t
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
error: defining existential type use restricts existential type by using the generic parameter `T` twice
|
||||
--> $DIR/generic_duplicate_param_use.rs:11:1
|
||||
|
|
||||
LL | / fn one<T: Debug>(t: T) -> Two<T, T> {
|
||||
LL | | //~^ ERROR defining existential type use restricts existential type
|
||||
LL | | t
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: could not find defining uses
|
||||
--> $DIR/generic_duplicate_param_use.rs:8:1
|
||||
|
|
||||
LL | existential type Two<T, U>: Debug;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
// compile-pass
|
||||
#![feature(existential_type)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
|
@ -9,6 +8,7 @@ fn main() {}
|
|||
existential type Two<T, U>: Debug;
|
||||
|
||||
fn one<T: Debug>(t: T) -> Two<T, T> {
|
||||
//~^ defining existential type use restricts existential type
|
||||
t
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
error: defining existential type use restricts existential type by using the generic parameter `T` twice
|
||||
--> $DIR/generic_duplicate_param_use2.rs:10:1
|
||||
|
|
||||
LL | / fn one<T: Debug>(t: T) -> Two<T, T> {
|
||||
LL | | //~^ defining existential type use restricts existential type
|
||||
LL | | t
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
// compile-pass
|
||||
#![feature(existential_type)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
|
@ -9,6 +8,7 @@ fn main() {}
|
|||
existential type Two<T, U>: Debug;
|
||||
|
||||
fn one<T: Debug>(t: T) -> Two<T, T> {
|
||||
//~^ defining existential type use restricts existential type
|
||||
t
|
||||
}
|
||||
|
||||
|
|
@ -17,5 +17,6 @@ fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
|
|||
}
|
||||
|
||||
fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
|
||||
//~^ concrete type's generic parameters differ from previous defining use
|
||||
u
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
error: defining existential type use restricts existential type by using the generic parameter `T` twice
|
||||
--> $DIR/generic_duplicate_param_use3.rs:10:1
|
||||
|
|
||||
LL | / fn one<T: Debug>(t: T) -> Two<T, T> {
|
||||
LL | | //~^ defining existential type use restricts existential type
|
||||
LL | | t
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: concrete type's generic parameters differ from previous defining use
|
||||
--> $DIR/generic_duplicate_param_use3.rs:19:1
|
||||
|
|
||||
LL | / fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
|
||||
LL | | //~^ concrete type's generic parameters differ from previous defining use
|
||||
LL | | u
|
||||
LL | | }
|
||||
| |_^
|
||||
|
|
||||
note: previous use here
|
||||
--> $DIR/generic_duplicate_param_use3.rs:15:1
|
||||
|
|
||||
LL | / fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
|
||||
LL | | t
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
// compile-pass
|
||||
#![feature(existential_type)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
|
@ -9,6 +8,7 @@ fn main() {}
|
|||
existential type Two<T, U>: Debug;
|
||||
|
||||
fn one<T: Debug>(t: T) -> Two<T, T> {
|
||||
//~^ ERROR defining existential type use restricts existential type
|
||||
t
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
error: defining existential type use restricts existential type by using the generic parameter `T` twice
|
||||
--> $DIR/generic_duplicate_param_use4.rs:10:1
|
||||
|
|
||||
LL | / fn one<T: Debug>(t: T) -> Two<T, T> {
|
||||
LL | | //~^ ERROR defining existential type use restricts existential type
|
||||
LL | | t
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#![feature(existential_type)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
fn main() {}
|
||||
|
||||
// test that unused generic parameters are ok
|
||||
existential type Two<T, U>: Debug;
|
||||
|
||||
fn two<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
|
||||
(t, u)
|
||||
}
|
||||
|
||||
fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
|
||||
//~^ concrete type differs from previous
|
||||
(u, t)
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
error: concrete type differs from previous defining existential type use
|
||||
--> $DIR/generic_duplicate_param_use5.rs:14:1
|
||||
|
|
||||
LL | / fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
|
||||
LL | | //~^ concrete type differs from previous
|
||||
LL | | (u, t)
|
||||
LL | | }
|
||||
| |_^
|
||||
|
|
||||
note: previous use here
|
||||
--> $DIR/generic_duplicate_param_use5.rs:10:1
|
||||
|
|
||||
LL | / fn two<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
|
||||
LL | | (t, u)
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#![feature(existential_type)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
fn main() {}
|
||||
|
||||
// test that unused generic parameters are ok
|
||||
existential type Two<T, U>: Debug;
|
||||
|
||||
fn two<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
|
||||
(t, t)
|
||||
}
|
||||
|
||||
fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
|
||||
//~^ concrete type differs from previous
|
||||
(u, t)
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
error: concrete type differs from previous defining existential type use
|
||||
--> $DIR/generic_duplicate_param_use6.rs:14:1
|
||||
|
|
||||
LL | / fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
|
||||
LL | | //~^ concrete type differs from previous
|
||||
LL | | (u, t)
|
||||
LL | | }
|
||||
| |_^
|
||||
|
|
||||
note: previous use here
|
||||
--> $DIR/generic_duplicate_param_use6.rs:10:1
|
||||
|
|
||||
LL | / fn two<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
|
||||
LL | | (t, t)
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// compile-pass
|
||||
#![feature(existential_type)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
fn main() {}
|
||||
|
||||
existential type Two<A, B>: Debug;
|
||||
|
||||
fn two<T: Debug + Copy, U>(t: T, u: U) -> Two<T, U> {
|
||||
(t, t)
|
||||
}
|
||||
|
||||
fn three<T: Debug, U>(t: T, t2: T, u: U) -> Two<T, U> {
|
||||
(t, t2)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue