summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-12-01 13:33:33 +0000
committerbors <bors@rust-lang.org>2021-12-01 13:33:33 +0000
commitf04a2f4b8e89eac1119061ea2055d33c97e618b4 (patch)
tree915594a7e1efa285136276bd9bd1a87b81be1365
parent26b45573be204da2cc0db12828b7a03c41c73793 (diff)
parent6952470095180e74d59ae372d06a75818368000b (diff)
downloadrust-f04a2f4b8e89eac1119061ea2055d33c97e618b4.tar.gz
Auto merge of #91255 - b-naber:normalization-ice, r=jackh276
Implement version of normalize_erasing_regions that allows for normalization failure Fixes https://github.com/rust-lang/rust/issues/59324 Fixes https://github.com/rust-lang/rust/issues/67684 Fixes https://github.com/rust-lang/rust/issues/69398 Fixes https://github.com/rust-lang/rust/issues/71113 Fixes https://github.com/rust-lang/rust/issues/82079 Fixes #85103 Fixes https://github.com/rust-lang/rust/issues/88856 Fixes #91231 Fixes https://github.com/rust-lang/rust/issues/91234 Previously we called `normalize_erasing_regions` inside `layout_of`. `normalize_erasing_regions` assumes that the normalization succeeds. Since some `layout_of` calls happen before typecheck has finished, we introduce a new variant that allows for returning an error.
-rw-r--r--compiler/rustc_lint/src/types.rs4
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs3
-rw-r--r--compiler/rustc_middle/src/query/mod.rs19
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs23
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs115
-rw-r--r--compiler/rustc_traits/src/normalize_erasing_regions.rs40
-rw-r--r--src/librustdoc/html/render/print_item.rs7
-rw-r--r--src/test/ui/associated-types/issue-59324.rs26
-rw-r--r--src/test/ui/associated-types/issue-59324.stderr69
-rw-r--r--src/test/ui/associated-types/issue-67684.rs62
-rw-r--r--src/test/ui/associated-types/issue-69398.rs21
-rw-r--r--src/test/ui/associated-types/issue-71113.rs16
-rw-r--r--src/test/ui/associated-types/issue-82079.rs121
-rw-r--r--src/test/ui/associated-types/issue-85103.rs9
-rw-r--r--src/test/ui/associated-types/issue-85103.stderr8
-rw-r--r--src/test/ui/associated-types/issue-88856.rs32
-rw-r--r--src/test/ui/associated-types/issue-91231.rs17
-rw-r--r--src/test/ui/associated-types/issue-91234.rs13
18 files changed, 600 insertions, 5 deletions
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 708cd56e068..b20f7357b35 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1337,7 +1337,9 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
let layout = match cx.layout_of(ty) {
Ok(layout) => layout,
Err(
- ty::layout::LayoutError::Unknown(_) | ty::layout::LayoutError::SizeOverflow(_),
+ ty::layout::LayoutError::Unknown(_)
+ | ty::layout::LayoutError::SizeOverflow(_)
+ | ty::layout::LayoutError::NormalizationFailure(_, _),
) => return,
};
let (variants, tag) = match layout.variants {
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 7a51bb4a1f3..8e4a17bfa65 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -492,9 +492,6 @@ impl dyn MachineStopType {
}
}
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(InterpError<'_>, 64);
-
pub enum InterpError<'tcx> {
/// The program caused undefined behavior.
UndefinedBehavior(UndefinedBehaviorInfo<'tcx>),
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 268a66b9926..8667a6bea11 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1644,6 +1644,11 @@ rustc_queries! {
desc { "normalizing `{:?}`", goal }
}
+ // FIXME: Implement `normalize_generic_arg_after_erasing_regions` and
+ // `normalize_mir_const_after_erasing_regions` in terms of
+ // `try_normalize_generic_arg_after_erasing_regions` and
+ // `try_normalize_mir_const_after_erasing_regions`, respectively.
+
/// Do not call this query directly: invoke `normalize_erasing_regions` instead.
query normalize_generic_arg_after_erasing_regions(
goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
@@ -1658,6 +1663,20 @@ rustc_queries! {
desc { "normalizing `{}`", goal.value }
}
+ /// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
+ query try_normalize_generic_arg_after_erasing_regions(
+ goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
+ ) -> Result<GenericArg<'tcx>, NoSolution> {
+ desc { "normalizing `{}`", goal.value }
+ }
+
+ /// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
+ query try_normalize_mir_const_after_erasing_regions(
+ goal: ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
+ ) -> Result<mir::ConstantKind<'tcx>, NoSolution> {
+ desc { "normalizing `{}`", goal.value }
+ }
+
query implied_outlives_bounds(
goal: CanonicalTyGoal<'tcx>
) -> Result<
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index b87e23af72b..57506bc6834 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1,5 +1,6 @@
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use crate::mir::{GeneratorLayout, GeneratorSavedLocal};
+use crate::ty::normalize_erasing_regions::NormalizationError;
use crate::ty::subst::Subst;
use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable};
use rustc_ast as ast;
@@ -199,6 +200,7 @@ pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
pub enum LayoutError<'tcx> {
Unknown(Ty<'tcx>),
SizeOverflow(Ty<'tcx>),
+ NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
}
impl<'tcx> fmt::Display for LayoutError<'tcx> {
@@ -208,16 +210,24 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
LayoutError::SizeOverflow(ty) => {
write!(f, "values of the type `{}` are too big for the current architecture", ty)
}
+ LayoutError::NormalizationFailure(t, e) => write!(
+ f,
+ "unable to determine layout for `{}` because `{}` cannot be normalized",
+ t,
+ e.get_type_for_failure()
+ ),
}
}
}
+#[instrument(skip(tcx, query), level = "debug")]
fn layout_of<'tcx>(
tcx: TyCtxt<'tcx>,
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> Result<TyAndLayout<'tcx>, LayoutError<'tcx>> {
ty::tls::with_related_context(tcx, move |icx| {
let (param_env, ty) = query.into_parts();
+ debug!(?ty);
if !tcx.recursion_limit().value_within_limit(icx.layout_depth) {
tcx.sess.fatal(&format!("overflow representing the type `{}`", ty));
@@ -229,7 +239,18 @@ fn layout_of<'tcx>(
ty::tls::enter_context(&icx, |_| {
let param_env = param_env.with_reveal_all_normalized(tcx);
let unnormalized_ty = ty;
- let ty = tcx.normalize_erasing_regions(param_env, ty);
+
+ // FIXME: We might want to have two different versions of `layout_of`:
+ // One that can be called after typecheck has completed and can use
+ // `normalize_erasing_regions` here and another one that can be called
+ // before typecheck has completed and uses `try_normalize_erasing_regions`.
+ let ty = match tcx.try_normalize_erasing_regions(param_env, ty) {
+ Ok(t) => t,
+ Err(normalization_error) => {
+ return Err(LayoutError::NormalizationFailure(ty, normalization_error));
+ }
+ };
+
if ty != unnormalized_ty {
// Ensure this layout is also cached for the normalized type.
return tcx.layout_of(param_env.and(ty));
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index e6f67adae93..fce7cbfbb3d 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -8,10 +8,28 @@
//! or constant found within. (This underlying query is what is cached.)
use crate::mir;
+use crate::traits::query::NoSolution;
use crate::ty::fold::{TypeFoldable, TypeFolder};
use crate::ty::subst::{Subst, SubstsRef};
use crate::ty::{self, Ty, TyCtxt};
+#[derive(Debug, Copy, Clone, HashStable, TyEncodable, TyDecodable)]
+pub enum NormalizationError<'tcx> {
+ Type(Ty<'tcx>),
+ Const(ty::Const<'tcx>),
+ ConstantKind(mir::ConstantKind<'tcx>),
+}
+
+impl<'tcx> NormalizationError<'tcx> {
+ pub fn get_type_for_failure(&self) -> String {
+ match self {
+ NormalizationError::Type(t) => format!("{}", t),
+ NormalizationError::Const(c) => format!("{}", c),
+ NormalizationError::ConstantKind(ck) => format!("{}", ck),
+ }
+ }
+}
+
impl<'tcx> TyCtxt<'tcx> {
/// Erase the regions in `value` and then fully normalize all the
/// types found within. The result will also have regions erased.
@@ -32,6 +50,8 @@ impl<'tcx> TyCtxt<'tcx> {
// Erase first before we do the real query -- this keeps the
// cache from being too polluted.
let value = self.erase_regions(value);
+ debug!(?value);
+
if !value.has_projections() {
value
} else {
@@ -41,6 +61,39 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
+ /// Tries to erase the regions in `value` and then fully normalize all the
+ /// types found within. The result will also have regions erased.
+ ///
+ /// Contrary to `normalize_erasing_regions` this function does not assume that normalization
+ /// succeeds.
+ pub fn try_normalize_erasing_regions<T>(
+ self,
+ param_env: ty::ParamEnv<'tcx>,
+ value: T,
+ ) -> Result<T, NormalizationError<'tcx>>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ debug!(
+ "try_normalize_erasing_regions::<{}>(value={:?}, param_env={:?})",
+ std::any::type_name::<T>(),
+ value,
+ param_env,
+ );
+
+ // Erase first before we do the real query -- this keeps the
+ // cache from being too polluted.
+ let value = self.erase_regions(value);
+ debug!(?value);
+
+ if !value.has_projections() {
+ Ok(value)
+ } else {
+ let mut folder = TryNormalizeAfterErasingRegionsFolder::new(self, param_env);
+ value.fold_with(&mut folder)
+ }
+ }
+
/// If you have a `Binder<'tcx, T>`, you can do this to strip out the
/// late-bound regions and then normalize the result, yielding up
/// a `T` (with regions erased). This is appropriate when the
@@ -91,11 +144,14 @@ struct NormalizeAfterErasingRegionsFolder<'tcx> {
}
impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> {
+ #[instrument(skip(self), level = "debug")]
fn normalize_generic_arg_after_erasing_regions(
&self,
arg: ty::GenericArg<'tcx>,
) -> ty::GenericArg<'tcx> {
let arg = self.param_env.and(arg);
+ debug!(?arg);
+
self.tcx.normalize_generic_arg_after_erasing_regions(arg)
}
}
@@ -126,3 +182,62 @@ impl TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
Ok(self.tcx.normalize_mir_const_after_erasing_regions(arg))
}
}
+
+struct TryNormalizeAfterErasingRegionsFolder<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+}
+
+impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> {
+ fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
+ TryNormalizeAfterErasingRegionsFolder { tcx, param_env }
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ fn try_normalize_generic_arg_after_erasing_regions(
+ &self,
+ arg: ty::GenericArg<'tcx>,
+ ) -> Result<ty::GenericArg<'tcx>, NoSolution> {
+ let arg = self.param_env.and(arg);
+ debug!(?arg);
+
+ self.tcx.try_normalize_generic_arg_after_erasing_regions(arg)
+ }
+}
+
+impl TypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> {
+ type Error = NormalizationError<'tcx>;
+
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ match self.try_normalize_generic_arg_after_erasing_regions(ty.into()) {
+ Ok(t) => Ok(t.expect_ty()),
+ Err(_) => Err(NormalizationError::Type(ty)),
+ }
+ }
+
+ fn fold_const(
+ &mut self,
+ c: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ match self.try_normalize_generic_arg_after_erasing_regions(c.into()) {
+ Ok(t) => Ok(t.expect_const()),
+ Err(_) => Err(NormalizationError::Const(*c)),
+ }
+ }
+
+ fn fold_mir_const(
+ &mut self,
+ c: mir::ConstantKind<'tcx>,
+ ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
+ // FIXME: This *probably* needs canonicalization too!
+ let arg = self.param_env.and(c);
+ match self.tcx.try_normalize_mir_const_after_erasing_regions(arg) {
+ Ok(c) => Ok(c),
+ Err(_) => Err(NormalizationError::ConstantKind(c)),
+ }
+ }
+}
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index 61ab5e28b67..4f35909df7f 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -20,6 +20,14 @@ crate fn provide(p: &mut Providers) {
normalize_mir_const_after_erasing_regions: |tcx, goal| {
normalize_after_erasing_regions(tcx, goal)
},
+ try_normalize_generic_arg_after_erasing_regions: |tcx, goal| {
+ debug!("try_normalize_generic_arg_after_erasing_regions(goal={:#?}", goal);
+
+ try_normalize_after_erasing_regions(tcx, goal)
+ },
+ try_normalize_mir_const_after_erasing_regions: |tcx, goal| {
+ try_normalize_after_erasing_regions(tcx, goal)
+ },
..*p
};
}
@@ -56,6 +64,38 @@ fn normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + Cop
})
}
+#[instrument(level = "debug", skip(tcx))]
+fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + Copy>(
+ tcx: TyCtxt<'tcx>,
+ goal: ParamEnvAnd<'tcx, T>,
+) -> Result<T, NoSolution> {
+ let ParamEnvAnd { param_env, value } = goal;
+ tcx.infer_ctxt().enter(|infcx| {
+ let cause = ObligationCause::dummy();
+ match infcx.at(&cause, param_env).normalize(value) {
+ Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => {
+ // We don't care about the `obligations`; they are
+ // always only region relations, and we are about to
+ // erase those anyway:
+ debug_assert_eq!(
+ normalized_obligations.iter().find(|p| not_outlives_predicate(&p.predicate)),
+ None,
+ );
+
+ let resolved_value = infcx.resolve_vars_if_possible(normalized_value);
+ // It's unclear when `resolve_vars` would have an effect in a
+ // fresh `InferCtxt`. If this assert does trigger, it will give
+ // us a test case.
+ debug_assert_eq!(normalized_value, resolved_value);
+ let erased = infcx.tcx.erase_regions(resolved_value);
+ debug_assert!(!erased.needs_infer(), "{:?}", erased);
+ Ok(erased)
+ }
+ Err(NoSolution) => Err(NoSolution),
+ }
+ })
+}
+
fn not_outlives_predicate(p: &ty::Predicate<'tcx>) -> bool {
match p.kind().skip_binder() {
ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::TypeOutlives(..) => false,
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index d3738cfa3e7..62fdec15af4 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1769,6 +1769,13 @@ fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) {
the type was too big.</p>"
);
}
+ Err(LayoutError::NormalizationFailure(_, _)) => {
+ writeln!(
+ w,
+ "<p><strong>Note:</strong> Encountered an error during type layout; \
+ the type failed to be normalized.</p>"
+ )
+ }
}
writeln!(w, "</div>");
diff --git a/src/test/ui/associated-types/issue-59324.rs b/src/test/ui/associated-types/issue-59324.rs
new file mode 100644
index 00000000000..9e68e9e7751
--- /dev/null
+++ b/src/test/ui/associated-types/issue-59324.rs
@@ -0,0 +1,26 @@
+trait NotFoo {}
+
+pub trait Foo: NotFoo {
+ type OnlyFoo;
+}
+
+pub trait Service {
+ type AssocType;
+}
+
+pub trait ThriftService<Bug: NotFoo>:
+//~^ ERROR the trait bound `Bug: Foo` is not satisfied
+//~| ERROR the trait bound `Bug: Foo` is not satisfied
+ Service<AssocType = <Bug as Foo>::OnlyFoo>
+{
+ fn get_service(
+ //~^ ERROR the trait bound `Bug: Foo` is not satisfied
+ //~| ERROR the trait bound `Bug: Foo` is not satisfied
+ &self,
+ ) -> Self::AssocType;
+}
+
+fn with_factory<H>(factory: dyn ThriftService<()>) {}
+//~^ ERROR the trait bound `(): Foo` is not satisfied
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-59324.stderr b/src/test/ui/associated-types/issue-59324.stderr
new file mode 100644
index 00000000000..2f430d3055e
--- /dev/null
+++ b/src/test/ui/associated-types/issue-59324.stderr
@@ -0,0 +1,69 @@
+error[E0277]: the trait bound `Bug: Foo` is not satisfied
+ --> $DIR/issue-59324.rs:11:1
+ |
+LL | / pub trait ThriftService<Bug: NotFoo>:
+LL | |
+LL | |
+LL | | Service<AssocType = <Bug as Foo>::OnlyFoo>
+... |
+LL | | ) -> Self::AssocType;
+LL | | }
+ | |_^ the trait `Foo` is not implemented for `Bug`
+ |
+help: consider further restricting this bound
+ |
+LL | pub trait ThriftService<Bug: NotFoo + Foo>:
+ | +++++
+
+error[E0277]: the trait bound `Bug: Foo` is not satisfied
+ --> $DIR/issue-59324.rs:11:1
+ |
+LL | / pub trait ThriftService<Bug: NotFoo>:
+LL | |
+LL | |
+LL | | Service<AssocType = <Bug as Foo>::OnlyFoo>
+... |
+LL | | ) -> Self::AssocType;
+LL | | }
+ | |_^ the trait `Foo` is not implemented for `Bug`
+ |
+help: consider further restricting this bound
+ |
+LL | pub trait ThriftService<Bug: NotFoo + Foo>:
+ | +++++
+
+error[E0277]: the trait bound `Bug: Foo` is not satisfied
+ --> $DIR/issue-59324.rs:16:5
+ |
+LL | / fn get_service(
+LL | |
+LL | |
+LL | | &self,
+LL | | ) -> Self::AssocType;
+ | |_________________________^ the trait `Foo` is not implemented for `Bug`
+ |
+help: consider further restricting this bound
+ |
+LL | pub trait ThriftService<Bug: NotFoo + Foo>:
+ | +++++
+
+error[E0277]: the trait bound `Bug: Foo` is not satisfied
+ --> $DIR/issue-59324.rs:16:8
+ |
+LL | fn get_service(
+ | ^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
+ |
+help: consider further restricting this bound
+ |
+LL | pub trait ThriftService<Bug: NotFoo + Foo>:
+ | +++++
+
+error[E0277]: the trait bound `(): Foo` is not satisfied
+ --> $DIR/issue-59324.rs:23:29
+ |
+LL | fn with_factory<H>(factory: dyn ThriftService<()>) {}
+ | ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/issue-67684.rs b/src/test/ui/associated-types/issue-67684.rs
new file mode 100644
index 00000000000..49efe8a1bda
--- /dev/null
+++ b/src/test/ui/associated-types/issue-67684.rs
@@ -0,0 +1,62 @@
+// check-pass
+
+#![allow(dead_code)]
+
+trait ParseError {
+ type StreamError;
+}
+
+impl<T> ParseError for T {
+ type StreamError = ();
+}
+
+trait Stream {
+ type Item;
+ type Error: ParseError;
+}
+
+trait Parser
+where
+ <Self as Parser>::PartialState: Default,
+{
+ type PartialState;
+ fn parse_mode(_: &Self, _: Self::PartialState) {
+ loop {}
+ }
+}
+
+impl Stream for () {
+ type Item = ();
+ type Error = ();
+}
+
+impl Parser for () {
+ type PartialState = ();
+}
+
+struct AndThen<A, B>(core::marker::PhantomData<(A, B)>);
+
+impl<A, B> Parser for AndThen<A, B>
+where
+ A: Stream,
+ B: Into<<A::Error as ParseError>::StreamError>,
+{
+ type PartialState = ();
+}
+
+fn expr<A>() -> impl Parser
+where
+ A: Stream<Error = <A as Stream>::Item>,
+{
+ AndThen::<A, ()>(core::marker::PhantomData)
+}
+
+fn parse_mode_impl<A>()
+where
+ <A as Stream>::Error: ParseError,
+ A: Stream<Error = <A as Stream>::Item>,
+{
+ Parser::parse_mode(&expr::<A>(), Default::default())
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-69398.rs b/src/test/ui/associated-types/issue-69398.rs
new file mode 100644
index 00000000000..ca3d66b1c8e
--- /dev/null
+++ b/src/test/ui/associated-types/issue-69398.rs
@@ -0,0 +1,21 @@
+// check-pass
+
+pub trait Foo {
+ type Bar;
+}
+
+pub trait Broken {
+ type Assoc;
+ fn broken(&self) where Self::Assoc: Foo;
+}
+
+impl<T> Broken for T {
+ type Assoc = ();
+ fn broken(&self) where Self::Assoc: Foo {
+ let _x: <Self::Assoc as Foo>::Bar;
+ }
+}
+
+fn main() {
+ let _m: &dyn Broken<Assoc=()> = &();
+}
diff --git a/src/test/ui/associated-types/issue-71113.rs b/src/test/ui/associated-types/issue-71113.rs
new file mode 100644
index 00000000000..48de89127f4
--- /dev/null
+++ b/src/test/ui/associated-types/issue-71113.rs
@@ -0,0 +1,16 @@
+// check-pass
+
+use std::borrow::Cow;
+
+enum _Recursive<'a>
+where
+ Self: ToOwned<Owned=Box<Self>>
+{
+ Variant(MyCow<'a, _Recursive<'a>>),
+}
+
+pub struct Wrapper<T>(T);
+
+pub struct MyCow<'a, T: ToOwned<Owned=Box<T>> + 'a>(Wrapper<Cow<'a, T>>);
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-82079.rs b/src/test/ui/associated-types/issue-82079.rs
new file mode 100644
index 00000000000..590c799c2d7
--- /dev/null
+++ b/src/test/ui/associated-types/issue-82079.rs
@@ -0,0 +1,121 @@
+// check-pass
+
+mod convenience_operators {
+ use crate::{Op, Relation};
+ use std::ops::AddAssign;
+ use std::ops::Mul;
+
+ impl<C: Op> Relation<C> {
+ pub fn map<F: Fn(C::D) -> D2 + 'static, D2: 'static>(
+ self,
+ f: F,
+ ) -> Relation<impl Op<D = D2, R = C::R>> {
+ self.map_dr(move |x, r| (f(x), r))
+ }
+ }
+
+ impl<K: 'static, V: 'static, C: Op<D = (K, V)>> Relation<C> {
+ pub fn semijoin<C2: Op<D = K, R = R2>, R2, R3: AddAssign<R3>>(
+ self,
+ other: Relation<C2>,
+ ) -> Relation<impl Op<D = C::D, R = R3>>
+ where
+ C::R: Mul<R2, Output = R3>,
+ {
+ self.join(other.map(|x| (x, ()))).map(|(k, x, ())| (k, x))
+ }
+ }
+}
+
+mod core {
+ mod operator {
+ mod join {
+ use super::Op;
+ use crate::core::Relation;
+ use std::ops::{AddAssign, Mul};
+ struct Join<LC, RC> {
+ _left: LC,
+ _right: RC,
+ }
+ impl<
+ LC: Op<D = (K, LD), R = LR>,
+ RC: Op<D = (K, RD), R = RR>,
+ K: 'static,
+ LD: 'static,
+ LR: AddAssign<LR> + Mul<RR, Output = OR>,
+ RD: 'static,
+ RR: AddAssign<RR>,
+ OR: AddAssign<OR>,
+ > Op for Join<LC, RC>
+ {
+ type D = (K, LD, RD);
+ type R = OR;
+ }
+ impl<K: 'static, D: 'static, C: Op<D = (K, D)>> Relation<C> {
+ pub fn join<C2: Op<D = (K, D2)>, D2: 'static, OR: AddAssign<OR>>(
+ self,
+ other: Relation<C2>,
+ ) -> Relation<impl Op<D = (K, D, D2), R = OR>>
+ where
+ C::R: Mul<C2::R, Output = OR>,
+ {
+ Relation {
+ inner: Join {
+ _left: self.inner,
+ _right: other.inner,
+ },
+ }
+ }
+ }
+ }
+ mod map {
+ use super::Op;
+ use crate::core::Relation;
+ use std::ops::AddAssign;
+ struct Map<C, MF> {
+ _inner: C,
+ _op: MF,
+ }
+ impl<
+ D1,
+ R1,
+ D2: 'static,
+ R2: AddAssign<R2>,
+ C: Op<D = D1, R = R1>,
+ MF: Fn(D1, R1) -> (D2, R2),
+ > Op for Map<C, MF>
+ {
+ type D = D2;
+ type R = R2;
+ }
+ impl<C: Op> Relation<C> {
+ pub fn map_dr<F: Fn(C::D, C::R) -> (D2, R2), D2: 'static, R2: AddAssign<R2>>(
+ self,
+ f: F,
+ ) -> Relation<impl Op<D = D2, R = R2>> {
+ Relation {
+ inner: Map {
+ _inner: self.inner,
+ _op: f,
+ },
+ }
+ }
+ }
+ }
+ use std::ops::AddAssign;
+ pub trait Op {
+ type D: 'static;
+ type R: AddAssign<Self::R>;
+ }
+ }
+ pub use self::operator::Op;
+ #[derive(Clone)]
+ pub struct Relation<C> {
+ inner: C,
+ }
+}
+
+use self::core::Op;
+pub use self::core::Relation;
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-85103.rs b/src/test/ui/associated-types/issue-85103.rs
new file mode 100644
index 00000000000..c5e13856178
--- /dev/null
+++ b/src/test/ui/associated-types/issue-85103.rs
@@ -0,0 +1,9 @@
+#![feature(rustc_attrs)]
+
+use std::borrow::Cow;
+
+#[rustc_layout(debug)]
+type Edges<'a, E> = Cow<'a, [E]>;
+//~^ ERROR layout error: NormalizationFailure
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-85103.stderr b/src/test/ui/associated-types/issue-85103.stderr
new file mode 100644
index 00000000000..142f3c411ec
--- /dev/null
+++ b/src/test/ui/associated-types/issue-85103.stderr
@@ -0,0 +1,8 @@
+error: layout error: NormalizationFailure(<[E] as std::borrow::ToOwned>::Owned, Type(<[E] as std::borrow::ToOwned>::Owned))
+ --> $DIR/issue-85103.rs:6:1
+ |
+LL | type Edges<'a, E> = Cow<'a, [E]>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/associated-types/issue-88856.rs b/src/test/ui/associated-types/issue-88856.rs
new file mode 100644
index 00000000000..7cae7c71cd2
--- /dev/null
+++ b/src/test/ui/associated-types/issue-88856.rs
@@ -0,0 +1,32 @@
+// check-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub trait Trait{
+ type R;
+ fn func(self)->Self::R;
+}
+
+pub struct TraitImpl<const N:usize>(pub i32);
+
+impl<const N:usize> Trait for TraitImpl<N>
+where [();N/2]:,
+{
+ type R = Self;
+ fn func(self)->Self::R {
+ self
+ }
+}
+
+fn sample<P,Convert>(p:P,f:Convert) -> i32
+where
+ P:Trait,Convert:Fn(P::R)->i32
+{
+ f(p.func())
+}
+
+fn main() {
+ let t = TraitImpl::<10>(4);
+ sample(t,|x|x.0);
+}
diff --git a/src/test/ui/associated-types/issue-91231.rs b/src/test/ui/associated-types/issue-91231.rs
new file mode 100644
index 00000000000..3c1cb81f097
--- /dev/null
+++ b/src/test/ui/associated-types/issue-91231.rs
@@ -0,0 +1,17 @@
+// check-pass
+
+#![feature(extern_types)]
+#![allow(dead_code)]
+
+extern {
+ type Extern;
+}
+
+trait Trait {
+ type Type;
+}
+
+#[inline]
+fn f<'a>(_: <&'a Extern as Trait>::Type) where &'a Extern: Trait {}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-91234.rs b/src/test/ui/associated-types/issue-91234.rs
new file mode 100644
index 00000000000..2f6c2d3aebd
--- /dev/null
+++ b/src/test/ui/associated-types/issue-91234.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+struct Struct;
+
+trait Trait {
+ type Type;
+}
+
+enum Enum<'a> where &'a Struct: Trait {
+ Variant(<&'a Struct as Trait>::Type)
+}
+
+fn main() {}