Auto merge of #112914 - matthiaskrgr:rollup-f0kdqh9, r=matthiaskrgr
Rollup of 4 pull requests Successful merges: - #112876 (Don't substitute a GAT that has mismatched generics in `OpaqueTypeCollector`) - #112906 (rustdoc: render the body of associated types before the where-clause) - #112907 (Update cargo) - #112908 (Print def_id on EarlyBoundRegion debug) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
0928a1f757
13 changed files with 207 additions and 82 deletions
|
@ -1584,7 +1584,7 @@ pub struct EarlyBoundRegion {
|
||||||
|
|
||||||
impl fmt::Debug for EarlyBoundRegion {
|
impl fmt::Debug for EarlyBoundRegion {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{}, {}", self.index, self.name)
|
write!(f, "{:?}, {}, {}", self.def_id, self.index, self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,12 +65,12 @@ pub use self::specialize::{
|
||||||
pub use self::structural_match::search_for_structural_match_violation;
|
pub use self::structural_match::search_for_structural_match_violation;
|
||||||
pub use self::structural_normalize::StructurallyNormalizeExt;
|
pub use self::structural_normalize::StructurallyNormalizeExt;
|
||||||
pub use self::util::elaborate;
|
pub use self::util::elaborate;
|
||||||
|
pub use self::util::{
|
||||||
|
check_substs_compatible, supertrait_def_ids, supertraits, transitive_bounds,
|
||||||
|
transitive_bounds_that_define_assoc_item, SupertraitDefIds,
|
||||||
|
};
|
||||||
pub use self::util::{expand_trait_aliases, TraitAliasExpander};
|
pub use self::util::{expand_trait_aliases, TraitAliasExpander};
|
||||||
pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices};
|
pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices};
|
||||||
pub use self::util::{
|
|
||||||
supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_item,
|
|
||||||
SupertraitDefIds,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub use self::chalk_fulfill::FulfillmentContext as ChalkFulfillmentContext;
|
pub use self::chalk_fulfill::FulfillmentContext as ChalkFulfillmentContext;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//! Code for projecting associated types out of trait references.
|
//! Code for projecting associated types out of trait references.
|
||||||
|
|
||||||
|
use super::check_substs_compatible;
|
||||||
use super::specialization_graph;
|
use super::specialization_graph;
|
||||||
use super::translate_substs;
|
use super::translate_substs;
|
||||||
use super::util;
|
use super::util;
|
||||||
|
@ -2378,47 +2379,6 @@ fn confirm_impl_candidate<'cx, 'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that the trait item and its implementation have compatible substs lists
|
|
||||||
fn check_substs_compatible<'tcx>(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
assoc_item: ty::AssocItem,
|
|
||||||
substs: ty::SubstsRef<'tcx>,
|
|
||||||
) -> bool {
|
|
||||||
fn check_substs_compatible_inner<'tcx>(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
generics: &'tcx ty::Generics,
|
|
||||||
args: &'tcx [ty::GenericArg<'tcx>],
|
|
||||||
) -> bool {
|
|
||||||
if generics.count() != args.len() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (parent_args, own_args) = args.split_at(generics.parent_count);
|
|
||||||
|
|
||||||
if let Some(parent) = generics.parent
|
|
||||||
&& let parent_generics = tcx.generics_of(parent)
|
|
||||||
&& !check_substs_compatible_inner(tcx, parent_generics, parent_args) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (param, arg) in std::iter::zip(&generics.params, own_args) {
|
|
||||||
match (¶m.kind, arg.unpack()) {
|
|
||||||
(ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_))
|
|
||||||
| (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_))
|
|
||||||
| (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {}
|
|
||||||
_ => return false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
let generics = tcx.generics_of(assoc_item.def_id);
|
|
||||||
// Chop off any additional substs (RPITIT) substs
|
|
||||||
let substs = &substs[0..generics.count().min(substs.len())];
|
|
||||||
check_substs_compatible_inner(tcx, generics, substs)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn confirm_impl_trait_in_trait_candidate<'tcx>(
|
fn confirm_impl_trait_in_trait_candidate<'tcx>(
|
||||||
selcx: &mut SelectionContext<'_, 'tcx>,
|
selcx: &mut SelectionContext<'_, 'tcx>,
|
||||||
obligation: &ProjectionTyObligation<'tcx>,
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
|
|
|
@ -302,3 +302,44 @@ pub enum TupleArgumentsFlag {
|
||||||
Yes,
|
Yes,
|
||||||
No,
|
No,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify that the trait item and its implementation have compatible substs lists
|
||||||
|
pub fn check_substs_compatible<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
assoc_item: ty::AssocItem,
|
||||||
|
substs: ty::SubstsRef<'tcx>,
|
||||||
|
) -> bool {
|
||||||
|
fn check_substs_compatible_inner<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
generics: &'tcx ty::Generics,
|
||||||
|
args: &'tcx [ty::GenericArg<'tcx>],
|
||||||
|
) -> bool {
|
||||||
|
if generics.count() != args.len() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (parent_args, own_args) = args.split_at(generics.parent_count);
|
||||||
|
|
||||||
|
if let Some(parent) = generics.parent
|
||||||
|
&& let parent_generics = tcx.generics_of(parent)
|
||||||
|
&& !check_substs_compatible_inner(tcx, parent_generics, parent_args) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (param, arg) in std::iter::zip(&generics.params, own_args) {
|
||||||
|
match (¶m.kind, arg.unpack()) {
|
||||||
|
(ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_))
|
||||||
|
| (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_))
|
||||||
|
| (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {}
|
||||||
|
_ => return false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
let generics = tcx.generics_of(assoc_item.def_id);
|
||||||
|
// Chop off any additional substs (RPITIT) substs
|
||||||
|
let substs = &substs[0..generics.count().min(substs.len())];
|
||||||
|
check_substs_compatible_inner(tcx, generics, substs)
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use rustc_middle::ty::util::{CheckRegions, NotUniqueParam};
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_type_ir::AliasKind;
|
use rustc_trait_selection::traits::check_substs_compatible;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
use crate::errors::{DuplicateArg, NotParam};
|
use crate::errors::{DuplicateArg, NotParam};
|
||||||
|
@ -36,6 +36,15 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
|
||||||
self.tcx.def_span(self.item)
|
self.tcx.def_span(self.item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parent_trait_ref(&self) -> Option<ty::TraitRef<'tcx>> {
|
||||||
|
let parent = self.parent()?;
|
||||||
|
if matches!(self.tcx.def_kind(parent), DefKind::Impl { .. }) {
|
||||||
|
Some(self.tcx.impl_trait_ref(parent)?.subst_identity())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parent(&self) -> Option<LocalDefId> {
|
fn parent(&self) -> Option<LocalDefId> {
|
||||||
match self.tcx.def_kind(self.item) {
|
match self.tcx.def_kind(self.item) {
|
||||||
DefKind::Fn => None,
|
DefKind::Fn => None,
|
||||||
|
@ -56,7 +65,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
|
||||||
#[instrument(skip(self), ret, level = "trace")]
|
#[instrument(skip(self), ret, level = "trace")]
|
||||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<ErrorGuaranteed> {
|
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<ErrorGuaranteed> {
|
||||||
match t.kind() {
|
match t.kind() {
|
||||||
ty::Alias(AliasKind::Opaque, alias_ty) if alias_ty.def_id.is_local() => {
|
ty::Alias(ty::Opaque, alias_ty) if alias_ty.def_id.is_local() => {
|
||||||
if !self.seen.insert(alias_ty.def_id.expect_local()) {
|
if !self.seen.insert(alias_ty.def_id.expect_local()) {
|
||||||
return ControlFlow::Continue(());
|
return ControlFlow::Continue(());
|
||||||
}
|
}
|
||||||
|
@ -98,37 +107,48 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::Alias(AliasKind::Projection, alias_ty) => {
|
ty::Alias(ty::Projection, alias_ty) => {
|
||||||
if let Some(parent) = self.parent() {
|
// This avoids having to do normalization of `Self::AssocTy` by only
|
||||||
trace!(?alias_ty);
|
// supporting the case of a method defining opaque types from assoc types
|
||||||
let (trait_ref, own_substs) = alias_ty.trait_ref_and_own_substs(self.tcx);
|
// in the same impl block.
|
||||||
|
if let Some(parent_trait_ref) = self.parent_trait_ref() {
|
||||||
|
// If the trait ref of the associated item and the impl differs,
|
||||||
|
// then we can't use the impl's identity substitutions below, so
|
||||||
|
// just skip.
|
||||||
|
if alias_ty.trait_ref(self.tcx) == parent_trait_ref {
|
||||||
|
let parent = self.parent().expect("we should have a parent here");
|
||||||
|
|
||||||
trace!(?trait_ref, ?own_substs);
|
for &assoc in self.tcx.associated_items(parent).in_definition_order() {
|
||||||
// This avoids having to do normalization of `Self::AssocTy` by only
|
|
||||||
// supporting the case of a method defining opaque types from assoc types
|
|
||||||
// in the same impl block.
|
|
||||||
if trait_ref.self_ty() == self.tcx.type_of(parent).subst_identity() {
|
|
||||||
for assoc in self.tcx.associated_items(parent).in_definition_order() {
|
|
||||||
trace!(?assoc);
|
trace!(?assoc);
|
||||||
if assoc.trait_item_def_id == Some(alias_ty.def_id) {
|
if assoc.trait_item_def_id != Some(alias_ty.def_id) {
|
||||||
// We reconstruct the generic args of the associated type within the impl
|
continue;
|
||||||
// from the impl's generics and the generic args passed to the type via the
|
|
||||||
// projection.
|
|
||||||
let substs = ty::InternalSubsts::identity_for_item(
|
|
||||||
self.tcx,
|
|
||||||
parent.to_def_id(),
|
|
||||||
);
|
|
||||||
trace!(?substs);
|
|
||||||
let substs: Vec<_> =
|
|
||||||
substs.iter().chain(own_substs.iter().copied()).collect();
|
|
||||||
trace!(?substs);
|
|
||||||
// Find opaque types in this associated type.
|
|
||||||
return self
|
|
||||||
.tcx
|
|
||||||
.type_of(assoc.def_id)
|
|
||||||
.subst(self.tcx, &substs)
|
|
||||||
.visit_with(self);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the type is further specializable, then the type_of
|
||||||
|
// is not actually correct below.
|
||||||
|
if !assoc.defaultness(self.tcx).is_final() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let impl_substs = alias_ty.substs.rebase_onto(
|
||||||
|
self.tcx,
|
||||||
|
parent_trait_ref.def_id,
|
||||||
|
ty::InternalSubsts::identity_for_item(self.tcx, parent),
|
||||||
|
);
|
||||||
|
|
||||||
|
if !check_substs_compatible(self.tcx, assoc, impl_substs) {
|
||||||
|
self.tcx.sess.delay_span_bug(
|
||||||
|
self.tcx.def_span(assoc.def_id),
|
||||||
|
"item had incorrect substs",
|
||||||
|
);
|
||||||
|
return ControlFlow::Continue(());
|
||||||
|
}
|
||||||
|
|
||||||
|
return self
|
||||||
|
.tcx
|
||||||
|
.type_of(assoc.def_id)
|
||||||
|
.subst(self.tcx, impl_substs)
|
||||||
|
.visit_with(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -799,10 +799,11 @@ fn assoc_type(
|
||||||
if !bounds.is_empty() {
|
if !bounds.is_empty() {
|
||||||
write!(w, ": {}", print_generic_bounds(bounds, cx))
|
write!(w, ": {}", print_generic_bounds(bounds, cx))
|
||||||
}
|
}
|
||||||
write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline));
|
// Render the default before the where-clause which aligns with the new recommended style. See #89122.
|
||||||
if let Some(default) = default {
|
if let Some(default) = default {
|
||||||
write!(w, " = {}", default.print(cx))
|
write!(w, " = {}", default.print(cx))
|
||||||
}
|
}
|
||||||
|
write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assoc_method(
|
fn assoc_method(
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit dead4b8740c4b6a8ed5211e37c99cf81d01c3b1c
|
Subproject commit 4cebd130ebca3bc219180a54f3e26cc1b14a91de
|
|
@ -23,9 +23,9 @@ impl LendingIterator for () {
|
||||||
pub struct Infinite<T>(T);
|
pub struct Infinite<T>(T);
|
||||||
|
|
||||||
// @has foo/trait.LendingIterator.html
|
// @has foo/trait.LendingIterator.html
|
||||||
// @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item<'a> where Self: 'a = &'a T"
|
// @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item<'a> = &'a T where Self: 'a"
|
||||||
impl<T> LendingIterator for Infinite<T> {
|
impl<T> LendingIterator for Infinite<T> {
|
||||||
type Item<'a> where Self: 'a = &'a T;
|
type Item<'a> = &'a T where Self: 'a;
|
||||||
|
|
||||||
fn next<'a>(&'a self) -> Self::Item<'a> {
|
fn next<'a>(&'a self) -> Self::Item<'a> {
|
||||||
&self.0
|
&self.0
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error[E0700]: hidden type for `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [ReEarlyBound(0, 'a), T, ReEarlyBound(0, 'a)])` captures lifetime that does not appear in bounds
|
error[E0700]: hidden type for `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [ReEarlyBound(DefId(0:9 ~ impl_trait_captures[aeb9]::foo::'a), 0, 'a), T, ReEarlyBound(DefId(0:9 ~ impl_trait_captures[aeb9]::foo::'a), 0, 'a)])` captures lifetime that does not appear in bounds
|
||||||
--> $DIR/impl-trait-captures.rs:11:5
|
--> $DIR/impl-trait-captures.rs:11:5
|
||||||
|
|
|
|
||||||
LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
|
LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
|
||||||
|
@ -8,7 +8,7 @@ LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
|
||||||
LL | x
|
LL | x
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
help: to declare that `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [ReEarlyBound(0, 'a), T, ReEarlyBound(2, 'a)])` captures `ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))` lifetime bound
|
help: to declare that `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [ReEarlyBound(DefId(0:9 ~ impl_trait_captures[aeb9]::foo::'a), 0, 'a), T, ReEarlyBound(DefId(0:14 ~ impl_trait_captures[aeb9]::foo::{opaque#0}::'a), 2, 'a)])` captures `ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))` lifetime bound
|
||||||
|
|
|
|
||||||
LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_)) {
|
LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_)) {
|
||||||
| ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
| ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
#![feature(impl_trait_in_assoc_type)]
|
||||||
|
|
||||||
|
// We weren't checking that the trait and impl generics line up in the
|
||||||
|
// normalization-shortcut code in `OpaqueTypeCollector`.
|
||||||
|
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
trait Foo {
|
||||||
|
type Bar<'a>;
|
||||||
|
|
||||||
|
type Baz<'a>;
|
||||||
|
|
||||||
|
fn test<'a>() -> Self::Bar<'a>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Foo for () {
|
||||||
|
type Bar<'a> = impl Deref<Target = Self::Baz<'a>>;
|
||||||
|
|
||||||
|
type Baz<T> = impl Sized;
|
||||||
|
//~^ ERROR type `Baz` has 1 type parameter but its trait declaration has 0 type parameters
|
||||||
|
//~| ERROR unconstrained opaque type
|
||||||
|
|
||||||
|
fn test<'a>() -> Self::Bar<'a> {
|
||||||
|
&()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,20 @@
|
||||||
|
error[E0049]: type `Baz` has 1 type parameter but its trait declaration has 0 type parameters
|
||||||
|
--> $DIR/impl-trait-in-type-alias-with-bad-substs.rs:19:14
|
||||||
|
|
|
||||||
|
LL | type Baz<'a>;
|
||||||
|
| -- expected 0 type parameters
|
||||||
|
...
|
||||||
|
LL | type Baz<T> = impl Sized;
|
||||||
|
| ^ found 1 type parameter
|
||||||
|
|
||||||
|
error: unconstrained opaque type
|
||||||
|
--> $DIR/impl-trait-in-type-alias-with-bad-substs.rs:19:19
|
||||||
|
|
|
||||||
|
LL | type Baz<T> = impl Sized;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `Baz` must be used in combination with a concrete type within the same impl
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0049`.
|
|
@ -0,0 +1,33 @@
|
||||||
|
#![feature(impl_trait_in_assoc_type)]
|
||||||
|
|
||||||
|
trait Foo<T> {
|
||||||
|
type Assoc;
|
||||||
|
|
||||||
|
fn test() -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DefinesOpaque;
|
||||||
|
impl Foo<DefinesOpaque> for () {
|
||||||
|
type Assoc = impl Sized;
|
||||||
|
|
||||||
|
// This test's return type is `u32`, *not* the opaque that is defined above.
|
||||||
|
// Previously we were only checking that the self type of the assoc matched,
|
||||||
|
// but this doesn't account for other impls with different trait substs.
|
||||||
|
fn test() -> <() as Foo<NoOpaques>>::Assoc {
|
||||||
|
let _: <Self as Foo<DefinesOpaque>>::Assoc = "";
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NoOpaques;
|
||||||
|
impl Foo<NoOpaques> for () {
|
||||||
|
type Assoc = u32;
|
||||||
|
|
||||||
|
fn test() -> u32 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,22 @@
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/not-matching-trait-refs-isnt-defining.rs:17:54
|
||||||
|
|
|
||||||
|
LL | type Assoc = impl Sized;
|
||||||
|
| ---------- the expected opaque type
|
||||||
|
...
|
||||||
|
LL | let _: <Self as Foo<DefinesOpaque>>::Assoc = "";
|
||||||
|
| ----------------------------------- ^^ expected opaque type, found `&str`
|
||||||
|
| |
|
||||||
|
| expected due to this
|
||||||
|
|
|
||||||
|
= note: expected opaque type `<() as Foo<DefinesOpaque>>::Assoc`
|
||||||
|
found reference `&'static str`
|
||||||
|
note: this item must have the opaque type in its signature in order to be able to register hidden types
|
||||||
|
--> $DIR/not-matching-trait-refs-isnt-defining.rs:16:5
|
||||||
|
|
|
||||||
|
LL | fn test() -> <() as Foo<NoOpaques>>::Assoc {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Add table
Add a link
Reference in a new issue