let tcx = self.infcx.tcx;
value.fold_with(&mut BottomUpFolder {
tcx,
+ reg_op: |reg| reg,
fldop: |ty| {
if let ty::TyAnon(def_id, substs) = ty.sty {
// Check that this is `impl Trait` type is
///////////////////////////////////////////////////////////////////////////
// Some sample folders
-pub struct BottomUpFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a, F>
- where F: FnMut(Ty<'tcx>) -> Ty<'tcx>
+pub struct BottomUpFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a, F, G>
+ where F: FnMut(Ty<'tcx>) -> Ty<'tcx>,
+ G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>,
{
pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
pub fldop: F,
+ pub reg_op: G,
}
-impl<'a, 'gcx, 'tcx, F> TypeFolder<'gcx, 'tcx> for BottomUpFolder<'a, 'gcx, 'tcx, F>
+impl<'a, 'gcx, 'tcx, F, G> TypeFolder<'gcx, 'tcx> for BottomUpFolder<'a, 'gcx, 'tcx, F, G>
where F: FnMut(Ty<'tcx>) -> Ty<'tcx>,
+ G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>,
{
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx }
let t1 = ty.super_fold_with(self);
(self.fldop)(t1)
}
+
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ let r = r.super_fold_with(self);
+ (self.reg_op)(r)
+ }
}
///////////////////////////////////////////////////////////////////////////
let anon_node_id = tcx.hir.as_local_node_id(def_id).unwrap();
if may_define_existential_type(tcx, fn_def_id, anon_node_id) {
trace!("check_existential_types may define. Generics: {:#?}", generics);
+ let mut seen: FxHashMap<_, Vec<_>> = FxHashMap();
for (subst, param) in substs.iter().zip(&generics.params) {
- if let ty::subst::UnpackedKind::Type(ty) = subst.unpack() {
- match ty.sty {
+ match subst.unpack() {
+ ty::subst::UnpackedKind::Type(ty) => match ty.sty {
ty::TyParam(..) => {},
// prevent `fn foo() -> Foo<u32>` from being defining
_ => {
),
)
.emit();
- return tcx.types.err;
},
- } // match ty
- } // if let Type = subst
+ }, // match ty
+ ty::subst::UnpackedKind::Lifetime(region) => {
+ let param_span = tcx.def_span(param.def_id);
+ if let ty::ReStatic = region {
+ tcx
+ .sess
+ .struct_span_err(
+ span,
+ "non-defining existential type use \
+ in defining scope",
+ )
+ .span_label(
+ param_span,
+ "cannot use static lifetime, use a bound lifetime \
+ instead or remove the lifetime parameter from the \
+ existential type",
+ )
+ .emit();
+ } else {
+ seen.entry(region).or_default().push(param_span);
+ }
+ },
+ } // match subst
} // for (subst, param)
+ for (_, spans) in seen {
+ if spans.len() > 1 {
+ tcx
+ .sess
+ .struct_span_err(
+ span,
+ "non-defining existential type use \
+ in defining scope",
+ ).
+ span_note(
+ spans,
+ "lifetime used multiple times",
+ )
+ .emit();
+ }
+ }
} // if may_define_existential_type
// now register the bounds on the parameters of the existential type
} // if let TyAnon
ty
},
+ reg_op: |reg| reg,
});
substituted_predicates
}
for (&def_id, anon_defn) in self.fcx.anon_types.borrow().iter() {
let node_id = self.tcx().hir.as_local_node_id(def_id).unwrap();
let instantiated_ty = self.resolve(&anon_defn.concrete_ty, &node_id);
- let mut definition_ty = self.fcx.infer_anon_definition_from_instantiation(
- def_id,
- anon_defn,
- instantiated_ty,
- );
let generics = self.tcx().generics_of(def_id);
- // named existential type, not an impl trait
- if generics.parent.is_none() {
+ let definition_ty = if generics.parent.is_some() {
+ // impl trait
+ self.fcx.infer_anon_definition_from_instantiation(
+ def_id,
+ anon_defn,
+ instantiated_ty,
+ )
+ } else {
// prevent
// * `fn foo<T>() -> Foo<T>`
// * `fn foo<T: Bound + Other>() -> Foo<T>`
// fn foo<U>() -> Foo<U> { .. }
// ```
// figures out the concrete type with `U`, but the stored type is with `T`
- definition_ty = definition_ty.fold_with(&mut BottomUpFolder {
+ instantiated_ty.fold_with(&mut BottomUpFolder {
tcx: self.tcx().global_tcx(),
fldop: |ty| {
+ trace!("checking type {:?}: {:#?}", ty, ty.sty);
// find a type parameter
if let ty::TyParam(..) = ty.sty {
// look it up in the substitution list
}
ty
},
- });
- }
+ reg_op: |region| {
+ match region {
+ // ignore static regions
+ ty::ReStatic => region,
+ _ => {
+ trace!("checking {:?}", region);
+ for (subst, p) in anon_defn.substs.iter().zip(&generics.params) {
+ if let UnpackedKind::Lifetime(subst) = subst.unpack() {
+ if subst == region {
+ // found it in the substitution list, replace with the
+ // parameter from the existential type
+ let reg = ty::EarlyBoundRegion {
+ def_id: p.def_id,
+ index: p.index,
+ name: p.name,
+ };
+ trace!("replace {:?} with {:?}", region, reg);
+ return self.tcx().global_tcx()
+ .mk_region(ty::ReEarlyBound(reg));
+ }
+ }
+ }
+ trace!("anon_defn: {:#?}", anon_defn);
+ trace!("generics: {:#?}", generics);
+ self.tcx().sess
+ .struct_span_err(
+ span,
+ "non-defining existential type use in defining scope",
+ )
+ .span_label(
+ span,
+ format!(
+ "lifetime `{}` is part of concrete type but not used \
+ in parameter list of existential type",
+ region,
+ ),
+ )
+ .emit();
+ self.tcx().global_tcx().mk_region(ty::ReStatic)
+ }
+ }
+ }
+ })
+ };
let old = self.tables.concrete_existential_types.insert(def_id, definition_ty);
if let Some(old) = old {
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+#![feature(existential_type)]
+
+fn main() {}
+
+existential type Two<'a, 'b>: std::fmt::Debug;
+
+fn one<'a>(t: &'a ()) -> Two<'a, 'a> { //~ ERROR non-defining existential type use
+ t
+}
--- /dev/null
+error: non-defining existential type use in defining scope
+ --> $DIR/generic_duplicate_lifetime_param.rs:18:1
+ |
+LL | / fn one<'a>(t: &'a ()) -> Two<'a, 'a> { //~ ERROR non-defining existential type use
+LL | | t
+LL | | }
+ | |_^
+ |
+note: lifetime used multiple times
+ --> $DIR/generic_duplicate_lifetime_param.rs:16:22
+ |
+LL | existential type Two<'a, 'b>: std::fmt::Debug;
+ | ^^ ^^
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+#![feature(existential_type)]
+
+fn main() {}
+
+existential type Two<T, U>: 'static; //~ ERROR type parameter `U` is unused
+
+fn one<T: 'static>(t: T) -> Two<T, T> {
+ t
+}
--- /dev/null
+error[E0091]: type parameter `U` is unused
+ --> $DIR/generic_duplicate_param_use.rs:16:25
+ |
+LL | existential type Two<T, U>: 'static; //~ ERROR type parameter `U` is unused
+ | ^ unused type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0091`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+
+#![feature(existential_type)]
+
+fn main() {}
+
+existential type Region<'a>: std::fmt::Debug;
+
+fn region<'b>(a: &'b ()) -> Region<'b> {
+ a
+}
fn main() {}
-mod boo2 {
- mod boo {
- pub existential type Boo: ::std::fmt::Debug;
- fn bomp() -> Boo {
- ""
- }
+mod boo {
+ pub existential type Boo: ::std::fmt::Debug;
+ fn bomp() -> Boo {
+ ""
}
+}
- // don't actually know the type here
+// don't actually know the type here
- fn bomp2() {
- let _: &str = bomp(); //~ ERROR mismatched types
- }
+fn bomp2() {
+ let _: &str = bomp(); //~ ERROR mismatched types
+}
- fn bomp() -> boo::Boo {
- "" //~ ERROR mismatched types
- }
+fn bomp() -> boo::Boo {
+ "" //~ ERROR mismatched types
}
+
+fn bomp_loop() -> boo::Boo {
+ loop {}
+}
\ No newline at end of file
error[E0308]: mismatched types
- --> $DIR/no_revealing_outside_defining_module.rs:27:23
+ --> $DIR/no_revealing_outside_defining_module.rs:26:19
|
-LL | let _: &str = bomp(); //~ ERROR mismatched types
- | ^^^^^^ expected &str, found anonymized type
+LL | let _: &str = bomp(); //~ ERROR mismatched types
+ | ^^^^^^ expected &str, found anonymized type
|
= note: expected type `&str`
found type `Boo`
error[E0308]: mismatched types
- --> $DIR/no_revealing_outside_defining_module.rs:31:9
+ --> $DIR/no_revealing_outside_defining_module.rs:30:5
|
-LL | fn bomp() -> boo::Boo {
- | -------- expected `Boo` because of return type
-LL | "" //~ ERROR mismatched types
- | ^^ expected anonymized type, found reference
+LL | fn bomp() -> boo::Boo {
+ | -------- expected `Boo` because of return type
+LL | "" //~ ERROR mismatched types
+ | ^^ expected anonymized type, found reference
|
= note: expected type `Boo`
found type `&'static str`