&anon_ty,
locations.span(body),
));
+
+ let revealed_ty_is_opaque = revealed_ty.is_impl_trait();
+
debug!(
"eq_opaque_type_and_type: \
instantiated output_ty={:?} \
opaque_type_map={:#?} \
- revealed_ty={:?}",
- output_ty, opaque_type_map, revealed_ty
+ revealed_ty={:?} \
+ revealed_ty_is_opaque={}",
+ output_ty, opaque_type_map, revealed_ty, revealed_ty_is_opaque
);
obligations.add(infcx
.at(&ObligationCause::dummy(), param_env)
.eq(output_ty, revealed_ty)?);
+ // This is 'true' when we're using an existential
+ // type without 'revelaing' it. For example, code like this:
+ //
+ // existential type Foo: Debug;
+ // fn foo1() -> Foo { ... }
+ // fn foo2() -> Foo { foo1() }
+ //
+ // In 'foo2', we're not revealing the type of 'Foo' - we're
+ // just treating it as the opaque type. All of the constraints
+ // in our 'opaque_type_map' apply to the concrete type,
+ // not to the opaque type itself. Therefore, it's enough
+ // to simply equate the output and opque 'revealed_type',
+ // as we do above
+ if revealed_ty_is_opaque {
+ return Ok(InferOk { value: None, obligations: obligations.into_vec() });
+ }
+
for (&opaque_def_id, opaque_decl) in &opaque_type_map {
let opaque_defn_ty = tcx.type_of(opaque_def_id);
let opaque_defn_ty = opaque_defn_ty.subst(tcx, opaque_decl.substs);
})
};
+ let mut skip_add = false;
+
if let ty::Opaque(defin_ty_def_id, _substs) = definition_ty.sty {
if def_id == defin_ty_def_id {
- // Concrete type resolved to the existential type itself.
- // Force a cycle error.
- // FIXME(oli-obk): we could just not insert it into `concrete_existential_types`
- // which simply would make this use not a defining use.
- self.tcx().at(span).type_of(defin_ty_def_id);
+ debug!("Skipping adding concrete definition for opaque type {:?} {:?}",
+ opaque_defn, defin_ty_def_id);
+ skip_add = true;
}
}
if !opaque_defn.substs.has_local_value() {
- let new = ty::ResolvedOpaqueTy {
- concrete_type: definition_ty,
- substs: opaque_defn.substs,
- };
-
- let old = self.tables
- .concrete_existential_types
- .insert(def_id, new);
- if let Some(old) = old {
- 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: {:?}, {:?}, {:?}, {:?}",
- def_id,
- definition_ty,
- opaque_defn,
- old,
- );
+ if !skip_add {
+ let new = ty::ResolvedOpaqueTy {
+ concrete_type: definition_ty,
+ substs: opaque_defn.substs,
+ };
+
+ let old = self.tables
+ .concrete_existential_types
+ .insert(def_id, new);
+ if let Some(old) = old {
+ 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: {:?}, {:?}, {:?}, {:?}",
+ def_id,
+ definition_ty,
+ opaque_defn,
+ old,
+ );
+ }
}
}
} else {
--- /dev/null
+#![feature(existential_type)]
+#![feature(impl_trait_in_bindings)]
+//~^ WARN the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+
+// Ensures that consts can constrain an existential type
+
+use std::fmt::Debug;
+
+// Type `Foo` refers to a type that implements the `Debug` trait.
+// The concrete type to which `Foo` refers is inferred from this module,
+// and this concrete type is hidden from outer modules (but not submodules).
+pub existential type Foo: Debug;
+
+const _FOO: Foo = 5;
+
+fn main() {
+}
--- /dev/null
+warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+ --> $DIR/existential_type_const.rs:2:12
+ |
+LL | #![feature(impl_trait_in_bindings)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
--- /dev/null
+#![feature(existential_type)]
+
+// Regression test for issue #61863
+
+pub trait MyTrait {}
+
+#[derive(Debug)]
+pub struct MyStruct {
+ v: u64
+}
+
+impl MyTrait for MyStruct {}
+
+pub fn bla() -> TE {
+ return MyStruct {v:1}
+}
+
+pub fn bla2() -> TE {
+ bla()
+}
+
+
+existential type TE: MyTrait;
+
+fn main() {}
#![feature(existential_type)]
existential type Foo: Fn() -> Foo;
-//~^ ERROR: cycle detected when processing `Foo`
+//~^ ERROR: could not find defining uses
fn crash(x: Foo) -> Foo {
x
-error[E0391]: cycle detected when processing `Foo`
+error: could not find defining uses
--> $DIR/existential-types-with-cycle-error.rs:3:1
|
LL | existential type Foo: Fn() -> Foo;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: ...which requires processing `crash`...
- --> $DIR/existential-types-with-cycle-error.rs:6:25
- |
-LL | fn crash(x: Foo) -> Foo {
- | _________________________^
-LL | | x
-LL | | }
- | |_^
- = note: ...which again requires processing `Foo`, completing the cycle
-note: cycle used when collecting item types in top-level module
- --> $DIR/existential-types-with-cycle-error.rs:1:1
- |
-LL | / #![feature(existential_type)]
-LL | |
-LL | | existential type Foo: Fn() -> Foo;
-LL | |
-... |
-LL | |
-LL | | }
- | |_^
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0391`.
}
existential type Foo: Bar<Foo, Item = Foo>;
-//~^ ERROR: cycle detected when processing `Foo`
+//~^ ERROR: could not find defining uses
fn crash(x: Foo) -> Foo {
x
-error[E0391]: cycle detected when processing `Foo`
+error: could not find defining uses
--> $DIR/existential-types-with-cycle-error2.rs:7:1
|
LL | existential type Foo: Bar<Foo, Item = Foo>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: ...which requires processing `crash`...
- --> $DIR/existential-types-with-cycle-error2.rs:10:25
- |
-LL | fn crash(x: Foo) -> Foo {
- | _________________________^
-LL | | x
-LL | | }
- | |_^
- = note: ...which again requires processing `Foo`, completing the cycle
-note: cycle used when collecting item types in top-level module
- --> $DIR/existential-types-with-cycle-error2.rs:1:1
- |
-LL | / #![feature(existential_type)]
-LL | |
-LL | | pub trait Bar<T> {
-LL | | type Item;
-... |
-LL | |
-LL | | }
- | |_^
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0391`.
-// Issue 52985: Cause cycle error if user code provides no use case that allows an existential type
-// to be inferred to a concrete type. This results in an infinite cycle during type normalization.
+// Issue 52985: user code provides no use case that allows an existential type
+// We now emit a 'could not find defining uses' error
#![feature(existential_type)]
-existential type Foo: Copy; //~ cycle detected
+existential type Foo: Copy; //~ could not find defining uses
// make compiler happy about using 'Foo'
fn bar(x: Foo) -> Foo { x }
-error[E0391]: cycle detected when processing `Foo`
+error: could not find defining uses
--> $DIR/no_inferrable_concrete_type.rs:6:1
|
LL | existential type Foo: Copy;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: ...which requires processing `bar`...
- --> $DIR/no_inferrable_concrete_type.rs:9:23
- |
-LL | fn bar(x: Foo) -> Foo { x }
- | ^^^^^
- = note: ...which again requires processing `Foo`, completing the cycle
-note: cycle used when collecting item types in top-level module
- --> $DIR/no_inferrable_concrete_type.rs:4:1
- |
-LL | / #![feature(existential_type)]
-LL | |
-LL | | existential type Foo: Copy;
-LL | |
-... |
-LL | | let _: Foo = std::mem::transmute(0u8);
-LL | | }
- | |_^
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0391`.