From 1025b3f16c2b23a01354eee8b7ae61a2d631a414 Mon Sep 17 00:00:00 2001 From: Samson <16504129+sagudev@users.noreply.github.com> Date: Sat, 11 May 2024 18:43:48 +0200 Subject: [PATCH 1/5] Update linker-plugin-lto.md to include LLVM 18 --- src/doc/rustc/src/linker-plugin-lto.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md index ff80f140482..ab95aa2e5a1 100644 --- a/src/doc/rustc/src/linker-plugin-lto.md +++ b/src/doc/rustc/src/linker-plugin-lto.md @@ -200,6 +200,7 @@ The following table shows known good combinations of toolchain versions. | 1.60 - 1.64 | 14 | | 1.65 - 1.69 | 15 | | 1.70 - 1.72 | 16 | -| 1.73 - 1.74 | 17 | +| 1.73 - 1.77 | 17 | +| 1.78 | 18 | Note that the compatibility policy for this feature might change in the future. From 488ddd3bbc2bb1d5956b3d677f3012694610a8c6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 16 May 2024 04:05:34 -0500 Subject: [PATCH 2/5] Fix assertion when attempting to convert `f16` and `f128` with `as` These types are currently rejected for `as` casts by the compiler. Remove this incorrect check and add codegen tests for all conversions involving these types. --- .../rustc_codegen_ssa/src/traits/builder.rs | 5 +- tests/codegen/float/f128.rs | 194 +++++++++++++++++ tests/codegen/float/f16.rs | 202 +++++++++++++++++- 3 files changed, 397 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index fdeccb90700..9fd6eb8edab 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -247,7 +247,10 @@ fn cast_float_to_int( } else { (in_ty, dest_ty) }; - assert!(matches!(self.cx().type_kind(float_ty), TypeKind::Float | TypeKind::Double)); + assert!(matches!( + self.cx().type_kind(float_ty), + TypeKind::Half | TypeKind::Float | TypeKind::Double | TypeKind::FP128 + )); assert_eq!(self.cx().type_kind(int_ty), TypeKind::Integer); if let Some(false) = self.cx().sess().opts.unstable_opts.saturating_float_casts { diff --git a/tests/codegen/float/f128.rs b/tests/codegen/float/f128.rs index 97d545e0283..32c5be1ec65 100644 --- a/tests/codegen/float/f128.rs +++ b/tests/codegen/float/f128.rs @@ -2,6 +2,7 @@ #![crate_type = "lib"] #![feature(f128)] +#![feature(f16)] #![feature(core_intrinsics)] // CHECK-LABEL: i1 @f128_eq( @@ -127,3 +128,196 @@ pub fn f128_rem_assign(a: &mut f128, b: f128) { // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}} *a %= b } + +/* float to float conversions */ + +// CHECK-LABEL: half @f128_as_f16( +#[no_mangle] +pub fn f128_as_f16(a: f128) -> f16 { + // CHECK: fptrunc fp128 %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: float @f128_as_f32( +#[no_mangle] +pub fn f128_as_f32(a: f128) -> f32 { + // CHECK: fptrunc fp128 %{{.+}} to float + a as f32 +} + +// CHECK-LABEL: double @f128_as_f64( +#[no_mangle] +pub fn f128_as_f64(a: f128) -> f64 { + // CHECK: fptrunc fp128 %{{.+}} to double + a as f64 +} + +// CHECK-LABEL: fp128 @f128_as_self( +#[no_mangle] +pub fn f128_as_self(a: f128) -> f128 { + // CHECK: ret fp128 %{{.+}} + a as f128 +} + +// CHECK-LABEL: fp128 @f16_as_f128( +#[no_mangle] +pub fn f16_as_f128(a: f16) -> f128 { + // CHECK: fpext half %{{.+}} to fp128 + a as f128 +} + +// CHECK-LABEL: fp128 @f32_as_f128( +#[no_mangle] +pub fn f32_as_f128(a: f32) -> f128 { + // CHECK: fpext float %{{.+}} to fp128 + a as f128 +} + +// CHECK-LABEL: fp128 @f64_as_f128( +#[no_mangle] +pub fn f64_as_f128(a: f64) -> f128 { + // CHECK: fpext double %{{.+}} to fp128 + a as f128 +} + +/* float to int conversions */ + +// CHECK-LABEL: i8 @f128_as_u8( +#[no_mangle] +pub fn f128_as_u8(a: f128) -> u8 { + // CHECK: call i8 @llvm.fptoui.sat.i8.f128(fp128 %{{.+}}) + a as u8 +} + +#[no_mangle] +pub fn f128_as_u16(a: f128) -> u16 { + // CHECK: call i16 @llvm.fptoui.sat.i16.f128(fp128 %{{.+}}) + a as u16 +} + +// CHECK-LABEL: i32 @f128_as_u32( +#[no_mangle] +pub fn f128_as_u32(a: f128) -> u32 { + // CHECK: call i32 @llvm.fptoui.sat.i32.f128(fp128 %{{.+}}) + a as u32 +} + +// CHECK-LABEL: i64 @f128_as_u64( +#[no_mangle] +pub fn f128_as_u64(a: f128) -> u64 { + // CHECK: call i64 @llvm.fptoui.sat.i64.f128(fp128 %{{.+}}) + a as u64 +} + +// CHECK-LABEL: i128 @f128_as_u128( +#[no_mangle] +pub fn f128_as_u128(a: f128) -> u128 { + // CHECK: call i128 @llvm.fptoui.sat.i128.f128(fp128 %{{.+}}) + a as u128 +} + +// CHECK-LABEL: i8 @f128_as_i8( +#[no_mangle] +pub fn f128_as_i8(a: f128) -> i8 { + // CHECK: call i8 @llvm.fptosi.sat.i8.f128(fp128 %{{.+}}) + a as i8 +} + +// CHECK-LABEL: i16 @f128_as_i16( +#[no_mangle] +pub fn f128_as_i16(a: f128) -> i16 { + // CHECK: call i16 @llvm.fptosi.sat.i16.f128(fp128 %{{.+}}) + a as i16 +} +// CHECK-LABEL: i32 @f128_as_i32( +#[no_mangle] +pub fn f128_as_i32(a: f128) -> i32 { + // CHECK: call i32 @llvm.fptosi.sat.i32.f128(fp128 %{{.+}}) + a as i32 +} + +// CHECK-LABEL: i64 @f128_as_i64( +#[no_mangle] +pub fn f128_as_i64(a: f128) -> i64 { + // CHECK: call i64 @llvm.fptosi.sat.i64.f128(fp128 %{{.+}}) + a as i64 +} + +// CHECK-LABEL: i128 @f128_as_i128( +#[no_mangle] +pub fn f128_as_i128(a: f128) -> i128 { + // CHECK: call i128 @llvm.fptosi.sat.i128.f128(fp128 %{{.+}}) + a as i128 +} + +/* int to float conversions */ + +// CHECK-LABEL: fp128 @u8_as_f128( +#[no_mangle] +pub fn u8_as_f128(a: u8) -> f128 { + // CHECK: uitofp i8 %{{.+}} to fp128 + a as f128 +} + +// CHECK-LABEL: fp128 @u16_as_f128( +#[no_mangle] +pub fn u16_as_f128(a: u16) -> f128 { + // CHECK: uitofp i16 %{{.+}} to fp128 + a as f128 +} + +// CHECK-LABEL: fp128 @u32_as_f128( +#[no_mangle] +pub fn u32_as_f128(a: u32) -> f128 { + // CHECK: uitofp i32 %{{.+}} to fp128 + a as f128 +} + +// CHECK-LABEL: fp128 @u64_as_f128( +#[no_mangle] +pub fn u64_as_f128(a: u64) -> f128 { + // CHECK: uitofp i64 %{{.+}} to fp128 + a as f128 +} + +// CHECK-LABEL: fp128 @u128_as_f128( +#[no_mangle] +pub fn u128_as_f128(a: u128) -> f128 { + // CHECK: uitofp i128 %{{.+}} to fp128 + a as f128 +} + +// CHECK-LABEL: fp128 @i8_as_f128( +#[no_mangle] +pub fn i8_as_f128(a: i8) -> f128 { + // CHECK: sitofp i8 %{{.+}} to fp128 + a as f128 +} + +// CHECK-LABEL: fp128 @i16_as_f128( +#[no_mangle] +pub fn i16_as_f128(a: i16) -> f128 { + // CHECK: sitofp i16 %{{.+}} to fp128 + a as f128 +} + +// CHECK-LABEL: fp128 @i32_as_f128( +#[no_mangle] +pub fn i32_as_f128(a: i32) -> f128 { + // CHECK: sitofp i32 %{{.+}} to fp128 + a as f128 +} + +// CHECK-LABEL: fp128 @i64_as_f128( +#[no_mangle] +pub fn i64_as_f128(a: i64) -> f128 { + // CHECK: sitofp i64 %{{.+}} to fp128 + a as f128 +} + +// CHECK-LABEL: fp128 @i128_as_f128( +#[no_mangle] +pub fn i128_as_f128(a: i128) -> f128 { + // CHECK: sitofp i128 %{{.+}} to fp128 + a as f128 +} diff --git a/tests/codegen/float/f16.rs b/tests/codegen/float/f16.rs index d1f75cc3b68..96daac869c2 100644 --- a/tests/codegen/float/f16.rs +++ b/tests/codegen/float/f16.rs @@ -1,9 +1,12 @@ // Verify that our intrinsics generate the correct LLVM calls for f16 #![crate_type = "lib"] +#![feature(f128)] #![feature(f16)] #![feature(core_intrinsics)] +/* arithmetic */ + // CHECK-LABEL: i1 @f16_eq( #[no_mangle] pub fn f16_eq(a: f16, b: f16) -> bool { @@ -109,7 +112,7 @@ pub fn f16_sub_assign(a: &mut f16, b: f16) { pub fn f16_mul_assign(a: &mut f16, b: f16) { // CHECK: fmul half %{{.+}}, %{{.+}} // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} - *a *= b + *a *= b; } // CHECK-LABEL: void @f16_div_assign( @@ -117,7 +120,7 @@ pub fn f16_mul_assign(a: &mut f16, b: f16) { pub fn f16_div_assign(a: &mut f16, b: f16) { // CHECK: fdiv half %{{.+}}, %{{.+}} // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} - *a /= b + *a /= b; } // CHECK-LABEL: void @f16_rem_assign( @@ -125,5 +128,198 @@ pub fn f16_div_assign(a: &mut f16, b: f16) { pub fn f16_rem_assign(a: &mut f16, b: f16) { // CHECK: frem half %{{.+}}, %{{.+}} // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} - *a %= b + *a %= b; +} + +/* float to float conversions */ + +// CHECK-LABEL: half @f16_as_self( +#[no_mangle] +pub fn f16_as_self(a: f16) -> f16 { + // CHECK: ret half %{{.+}} + a as f16 +} + +// CHECK-LABEL: float @f16_as_f32( +#[no_mangle] +pub fn f16_as_f32(a: f16) -> f32 { + // CHECK: fpext half %{{.+}} to float + a as f32 +} + +// CHECK-LABEL: double @f16_as_f64( +#[no_mangle] +pub fn f16_as_f64(a: f16) -> f64 { + // CHECK: fpext half %{{.+}} to double + a as f64 +} + +// CHECK-LABEL: fp128 @f16_as_f128( +#[no_mangle] +pub fn f16_as_f128(a: f16) -> f128 { + // CHECK: fpext half %{{.+}} to fp128 + a as f128 +} + +// CHECK-LABEL: half @f32_as_f16( +#[no_mangle] +pub fn f32_as_f16(a: f32) -> f16 { + // CHECK: fptrunc float %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: half @f64_as_f16( +#[no_mangle] +pub fn f64_as_f16(a: f64) -> f16 { + // CHECK: fptrunc double %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: half @f128_as_f16( +#[no_mangle] +pub fn f128_as_f16(a: f128) -> f16 { + // CHECK: fptrunc fp128 %{{.+}} to half + a as f16 +} + +/* float to int conversions */ + +// CHECK-LABEL: i8 @f16_as_u8( +#[no_mangle] +pub fn f16_as_u8(a: f16) -> u8 { + // CHECK: call i8 @llvm.fptoui.sat.i8.f16(half %{{.+}}) + a as u8 +} + +#[no_mangle] +pub fn f16_as_u16(a: f16) -> u16 { + // CHECK: call i16 @llvm.fptoui.sat.i16.f16(half %{{.+}}) + a as u16 +} + +// CHECK-LABEL: i32 @f16_as_u32( +#[no_mangle] +pub fn f16_as_u32(a: f16) -> u32 { + // CHECK: call i32 @llvm.fptoui.sat.i32.f16(half %{{.+}}) + a as u32 +} + +// CHECK-LABEL: i64 @f16_as_u64( +#[no_mangle] +pub fn f16_as_u64(a: f16) -> u64 { + // CHECK: call i64 @llvm.fptoui.sat.i64.f16(half %{{.+}}) + a as u64 +} + +// CHECK-LABEL: i128 @f16_as_u128( +#[no_mangle] +pub fn f16_as_u128(a: f16) -> u128 { + // CHECK: call i128 @llvm.fptoui.sat.i128.f16(half %{{.+}}) + a as u128 +} + +// CHECK-LABEL: i8 @f16_as_i8( +#[no_mangle] +pub fn f16_as_i8(a: f16) -> i8 { + // CHECK: call i8 @llvm.fptosi.sat.i8.f16(half %{{.+}}) + a as i8 +} + +// CHECK-LABEL: i16 @f16_as_i16( +#[no_mangle] +pub fn f16_as_i16(a: f16) -> i16 { + // CHECK: call i16 @llvm.fptosi.sat.i16.f16(half %{{.+}}) + a as i16 +} +// CHECK-LABEL: i32 @f16_as_i32( +#[no_mangle] +pub fn f16_as_i32(a: f16) -> i32 { + // CHECK: call i32 @llvm.fptosi.sat.i32.f16(half %{{.+}}) + a as i32 +} + +// CHECK-LABEL: i64 @f16_as_i64( +#[no_mangle] +pub fn f16_as_i64(a: f16) -> i64 { + // CHECK: call i64 @llvm.fptosi.sat.i64.f16(half %{{.+}}) + a as i64 +} + +// CHECK-LABEL: i128 @f16_as_i128( +#[no_mangle] +pub fn f16_as_i128(a: f16) -> i128 { + // CHECK: call i128 @llvm.fptosi.sat.i128.f16(half %{{.+}}) + a as i128 +} + +/* int to float conversions */ + +// CHECK-LABEL: half @u8_as_f16( +#[no_mangle] +pub fn u8_as_f16(a: u8) -> f16 { + // CHECK: uitofp i8 %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: half @u16_as_f16( +#[no_mangle] +pub fn u16_as_f16(a: u16) -> f16 { + // CHECK: uitofp i16 %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: half @u32_as_f16( +#[no_mangle] +pub fn u32_as_f16(a: u32) -> f16 { + // CHECK: uitofp i32 %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: half @u64_as_f16( +#[no_mangle] +pub fn u64_as_f16(a: u64) -> f16 { + // CHECK: uitofp i64 %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: half @u128_as_f16( +#[no_mangle] +pub fn u128_as_f16(a: u128) -> f16 { + // CHECK: uitofp i128 %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: half @i8_as_f16( +#[no_mangle] +pub fn i8_as_f16(a: i8) -> f16 { + // CHECK: sitofp i8 %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: half @i16_as_f16( +#[no_mangle] +pub fn i16_as_f16(a: i16) -> f16 { + // CHECK: sitofp i16 %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: half @i32_as_f16( +#[no_mangle] +pub fn i32_as_f16(a: i32) -> f16 { + // CHECK: sitofp i32 %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: half @i64_as_f16( +#[no_mangle] +pub fn i64_as_f16(a: i64) -> f16 { + // CHECK: sitofp i64 %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: half @i128_as_f16( +#[no_mangle] +pub fn i128_as_f16(a: i128) -> f16 { + // CHECK: sitofp i128 %{{.+}} to half + a as f16 } From 504bca9ee651cbc8d64a8e0f3cdfad0315478350 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Tue, 14 May 2024 20:50:05 +0000 Subject: [PATCH 3/5] rustdoc-json-types: Document `Id` --- src/rustdoc-json-types/lib.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 164f88faa31..a9882be930c 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -188,7 +188,19 @@ pub enum TypeBindingKind { Constraint(Vec), } +/// An opaque identifier for an item. +/// +/// It can be used to lookup in [Crate::index] or [Crate::paths] to resolve it +/// to an [Item]. +/// +/// Id's are only valid within a single JSON blob. They cannot be used to +/// resolve references between the JSON output's for different crates. +/// +/// Rustdoc makes no guarantees about the inner value of Id's. Applications +/// should treat them as opaque keys to lookup items, and avoid attempting +/// to parse them, or otherwise depend on any implementation details. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +// FIXME(aDotInTheVoid): Consider making this non-public in rustdoc-types. pub struct Id(pub String); #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] From 312ba4da3c9c39f2a70941e0c79c1366166ebef0 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 15 May 2024 13:54:37 -0400 Subject: [PATCH 4/5] Uplift FnSig --- compiler/rustc_errors/src/diagnostic_impls.rs | 6 ++ compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 26 +++++- compiler/rustc_middle/src/ty/print/pretty.rs | 20 ++--- .../rustc_middle/src/ty/structural_impls.rs | 43 ---------- compiler/rustc_middle/src/ty/sty.rs | 73 +++++------------ compiler/rustc_type_ir/src/inherent.rs | 15 ++++ compiler/rustc_type_ir/src/interner.rs | 17 ++-- compiler/rustc_type_ir/src/ir_print.rs | 5 +- compiler/rustc_type_ir/src/predicate.rs | 2 +- compiler/rustc_type_ir/src/ty_kind.rs | 81 ++++++++++++++++++- 11 files changed, 168 insertions(+), 122 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index d9add1c9b3b..4bf7dccab92 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -112,6 +112,12 @@ fn into_diag_arg(self) -> rustc_errors::DiagArgValue { } } +impl IntoDiagArg for rustc_type_ir::FnSig { + fn into_diag_arg(self) -> rustc_errors::DiagArgValue { + format!("{self:?}").into_diag_arg() + } +} + into_diag_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize); impl IntoDiagArg for bool { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 6e4cef068c5..904abe45a23 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3191,7 +3191,7 @@ pub enum Unsafety { } impl Unsafety { - pub fn prefix_str(&self) -> &'static str { + pub fn prefix_str(self) -> &'static str { match self { Self::Unsafe => "unsafe ", Self::Normal => "", diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index d7e185dd5e1..6f70231337a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -92,7 +92,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type DefiningOpaqueTypes = &'tcx ty::List; type AdtDef = ty::AdtDef<'tcx>; type GenericArgs = ty::GenericArgsRef<'tcx>; - type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>]; + type OwnItemArgs = &'tcx [ty::GenericArg<'tcx>]; type GenericArg = ty::GenericArg<'tcx>; type Term = ty::Term<'tcx>; @@ -103,6 +103,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type CanonicalVars = CanonicalVarInfos<'tcx>; type Ty = Ty<'tcx>; type Tys = &'tcx List>; + type FnInputTys = &'tcx [Ty<'tcx>]; type ParamTy = ParamTy; type BoundTy = ty::BoundTy; type PlaceholderTy = ty::PlaceholderType; @@ -113,21 +114,24 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type AllocId = crate::mir::interpret::AllocId; type Pat = Pattern<'tcx>; + type Unsafety = hir::Unsafety; + type Abi = abi::Abi; + type Const = ty::Const<'tcx>; type AliasConst = ty::UnevaluatedConst<'tcx>; type PlaceholderConst = ty::PlaceholderConst; type ParamConst = ty::ParamConst; type BoundConst = ty::BoundVar; type ValueConst = ty::ValTree<'tcx>; - type ExprConst = ty::Expr<'tcx>; + type Region = Region<'tcx>; type EarlyParamRegion = ty::EarlyParamRegion; type LateParamRegion = ty::LateParamRegion; type BoundRegion = ty::BoundRegion; type InferRegion = ty::RegionVid; - type PlaceholderRegion = ty::PlaceholderRegion; + type Predicate = Predicate<'tcx>; type TraitPredicate = ty::TraitPredicate<'tcx>; type RegionOutlivesPredicate = ty::RegionOutlivesPredicate<'tcx>; @@ -135,10 +139,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type ProjectionPredicate = ty::ProjectionPredicate<'tcx>; type NormalizesTo = ty::NormalizesTo<'tcx>; type SubtypePredicate = ty::SubtypePredicate<'tcx>; + type CoercePredicate = ty::CoercePredicate<'tcx>; type ClosureKind = ty::ClosureKind; type Clauses = ty::Clauses<'tcx>; + fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo]) -> Self::CanonicalVars { self.mk_canonical_var_infos(infos) } @@ -191,7 +197,7 @@ fn trait_ref_and_own_args_for_alias( self, def_id: Self::DefId, args: Self::GenericArgs, - ) -> (rustc_type_ir::TraitRef, Self::GenericArgsSlice) { + ) -> (rustc_type_ir::TraitRef, Self::OwnItemArgs) { assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst); let trait_def_id = self.parent(def_id); assert_matches!(self.def_kind(trait_def_id), DefKind::Trait); @@ -223,6 +229,18 @@ fn parent(self, def_id: Self::DefId) -> Self::DefId { } } +impl<'tcx> rustc_type_ir::inherent::Abi> for abi::Abi { + fn is_rust(self) -> bool { + matches!(self, abi::Abi::Rust) + } +} + +impl<'tcx> rustc_type_ir::inherent::Unsafety> for hir::Unsafety { + fn prefix_str(self) -> &'static str { + self.prefix_str() + } +} + type InternedSet<'tcx, T> = ShardedHashMap, ()>; pub struct CtxtInterners<'tcx> { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 3577db7234d..d9043d43cd7 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3034,6 +3034,16 @@ macro_rules! define_print_and_forward_display { define_print! { (self, cx): + ty::FnSig<'tcx> { + p!(write("{}", self.unsafety.prefix_str())); + + if self.abi != Abi::Rust { + p!(write("extern {} ", self.abi)); + } + + p!("fn", pretty_fn_sig(self.inputs(), self.c_variadic, self.output())); + } + ty::TraitRef<'tcx> { p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path())) } @@ -3169,16 +3179,6 @@ macro_rules! define_print_and_forward_display { p!("{{", comma_sep(self.iter()), "}}") } - ty::FnSig<'tcx> { - p!(write("{}", self.unsafety.prefix_str())); - - if self.abi != Abi::Rust { - p!(write("extern {} ", self.abi)); - } - - p!("fn", pretty_fn_sig(self.inputs(), self.c_variadic, self.output())); - } - TraitRefPrintOnlyTraitPath<'tcx> { p!(print_def_path(self.0.def_id, self.0.args)); } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 7523cd15320..eed11422a44 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -83,49 +83,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } -impl<'tcx> fmt::Debug for ty::FnSig<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - WithInfcx::with_no_infcx(self).fmt(f) - } -} -impl<'tcx> DebugWithInfcx> for ty::FnSig<'tcx> { - fn fmt>>( - this: WithInfcx<'_, Infcx, &Self>, - f: &mut core::fmt::Formatter<'_>, - ) -> core::fmt::Result { - let sig = this.data; - let ty::FnSig { inputs_and_output: _, c_variadic, unsafety, abi } = sig; - - write!(f, "{}", unsafety.prefix_str())?; - match abi { - rustc_target::spec::abi::Abi::Rust => (), - abi => write!(f, "extern \"{abi:?}\" ")?, - }; - - write!(f, "fn(")?; - let inputs = sig.inputs(); - match inputs.len() { - 0 if *c_variadic => write!(f, "...)")?, - 0 => write!(f, ")")?, - _ => { - for ty in &sig.inputs()[0..(sig.inputs().len() - 1)] { - write!(f, "{:?}, ", &this.wrap(ty))?; - } - write!(f, "{:?}", &this.wrap(sig.inputs().last().unwrap()))?; - if *c_variadic { - write!(f, "...")?; - } - write!(f, ")")?; - } - } - - match sig.output().kind() { - ty::Tuple(list) if list.is_empty() => Ok(()), - _ => write!(f, " -> {:?}", &this.wrap(sig.output())), - } - } -} - impl<'tcx> ty::DebugWithInfcx> for Ty<'tcx> { fn fmt>>( this: WithInfcx<'_, Infcx, &Self>, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 74b03d6db66..9dbcd938e6e 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -39,6 +39,7 @@ pub type TyKind<'tcx> = ir::TyKind>; pub type TypeAndMut<'tcx> = ir::TypeAndMut>; pub type AliasTy<'tcx> = ir::AliasTy>; +pub type FnSig<'tcx> = ir::FnSig>; pub trait Article { fn article(&self) -> &'static str; @@ -985,14 +986,6 @@ pub fn as_deref(&self) -> Binder<'tcx, &T::Target> Binder { value: &self.value, bound_vars: self.bound_vars } } - pub fn map_bound_ref_unchecked(&self, f: F) -> Binder<'tcx, U> - where - F: FnOnce(&T) -> U, - { - let value = f(&self.value); - Binder { value, bound_vars: self.bound_vars } - } - pub fn map_bound_ref>>(&self, f: F) -> Binder<'tcx, U> where F: FnOnce(&T) -> U, @@ -1109,73 +1102,37 @@ pub struct GenSig<'tcx> { pub return_ty: Ty<'tcx>, } -/// Signature of a function type, which we have arbitrarily -/// decided to use to refer to the input/output types. -/// -/// - `inputs`: is the list of arguments and their modes. -/// - `output`: is the return type. -/// - `c_variadic`: indicates whether this is a C-variadic function. -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct FnSig<'tcx> { - pub inputs_and_output: &'tcx List>, - pub c_variadic: bool, - pub unsafety: hir::Unsafety, - pub abi: abi::Abi, -} - -impl<'tcx> FnSig<'tcx> { - pub fn inputs(&self) -> &'tcx [Ty<'tcx>] { - &self.inputs_and_output[..self.inputs_and_output.len() - 1] - } - - pub fn output(&self) -> Ty<'tcx> { - self.inputs_and_output[self.inputs_and_output.len() - 1] - } - - // Creates a minimal `FnSig` to be used when encountering a `TyKind::Error` in a fallible - // method. - fn fake() -> FnSig<'tcx> { - FnSig { - inputs_and_output: List::empty(), - c_variadic: false, - unsafety: hir::Unsafety::Normal, - abi: abi::Abi::Rust, - } - } -} - -impl<'tcx> IntoDiagArg for FnSig<'tcx> { - fn into_diag_arg(self) -> DiagArgValue { - self.to_string().into_diag_arg() - } -} - pub type PolyFnSig<'tcx> = Binder<'tcx, FnSig<'tcx>>; impl<'tcx> PolyFnSig<'tcx> { #[inline] pub fn inputs(&self) -> Binder<'tcx, &'tcx [Ty<'tcx>]> { - self.map_bound_ref_unchecked(|fn_sig| fn_sig.inputs()) + self.map_bound_ref(|fn_sig| fn_sig.inputs()) } + #[inline] #[track_caller] pub fn input(&self, index: usize) -> ty::Binder<'tcx, Ty<'tcx>> { self.map_bound_ref(|fn_sig| fn_sig.inputs()[index]) } + pub fn inputs_and_output(&self) -> ty::Binder<'tcx, &'tcx List>> { self.map_bound_ref(|fn_sig| fn_sig.inputs_and_output) } + #[inline] pub fn output(&self) -> ty::Binder<'tcx, Ty<'tcx>> { self.map_bound_ref(|fn_sig| fn_sig.output()) } + pub fn c_variadic(&self) -> bool { self.skip_binder().c_variadic } + pub fn unsafety(&self) -> hir::Unsafety { self.skip_binder().unsafety } + pub fn abi(&self) -> abi::Abi { self.skip_binder().abi } @@ -2031,7 +1988,12 @@ pub fn fn_sig(self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> { FnPtr(f) => *f, Error(_) => { // ignore errors (#54954) - ty::Binder::dummy(FnSig::fake()) + ty::Binder::dummy(ty::FnSig { + inputs_and_output: ty::List::empty(), + c_variadic: false, + unsafety: hir::Unsafety::Normal, + abi: abi::Abi::Rust, + }) } Closure(..) => bug!( "to get the signature of a closure, use `args.as_closure().sig()` not `fn_sig()`", @@ -2624,6 +2586,13 @@ pub fn is_known_rigid(self) -> bool { } } +impl<'tcx> rustc_type_ir::inherent::Tys> for &'tcx ty::List> { + fn split_inputs_and_output(self) -> (&'tcx [Ty<'tcx>], Ty<'tcx>) { + let (output, inputs) = self.split_last().unwrap(); + (inputs, *output) + } +} + /// Extra information about why we ended up with a particular variance. /// This is only used to add more information to error messages, and /// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo` diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 92b1e08ab0a..484f6c31258 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -26,6 +26,21 @@ pub trait Ty>: fn new_alias(interner: I, kind: AliasTyKind, alias_ty: AliasTy) -> Self; } +pub trait Tys>: + Copy + Debug + Hash + Eq + IntoIterator + Deref> +{ + fn split_inputs_and_output(self) -> (I::FnInputTys, I::Ty); +} + +pub trait Abi>: Copy + Debug + Hash + Eq { + /// Whether this ABI is `extern "Rust"`. + fn is_rust(self) -> bool; +} + +pub trait Unsafety>: Copy + Debug + Hash + Eq { + fn prefix_str(self) -> &'static str; +} + pub trait Region>: Copy + DebugWithInfcx + Hash + Eq + Into + IntoKind> + Flags { diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index d6680977168..c0179d33ac5 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -1,14 +1,15 @@ use smallvec::SmallVec; use std::fmt::Debug; use std::hash::Hash; +use std::ops::Deref; use crate::inherent::*; use crate::ir_print::IrPrint; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{ AliasTerm, AliasTermKind, AliasTy, AliasTyKind, CanonicalVarInfo, CoercePredicate, - DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, NormalizesTo, ProjectionPredicate, - SubtypePredicate, TraitPredicate, TraitRef, + DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, FnSig, NormalizesTo, + ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, }; pub trait Interner: @@ -24,13 +25,16 @@ pub trait Interner: + IrPrint> + IrPrint> + IrPrint> + + IrPrint> { type DefId: Copy + Debug + Hash + Eq; type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable; type AdtDef: Copy + Debug + Hash + Eq; type GenericArgs: GenericArgs; - type GenericArgsSlice: Copy + Debug + Hash + Eq; + /// The slice of args for a specific item. For a GAT like `type Foo<'a>`, it will be `['a]`, + /// not including the args from the parent item (trait or impl). + type OwnItemArgs: Copy + Debug + Hash + Eq; type GenericArg: Copy + DebugWithInfcx + Hash + Eq; type Term: Copy + Debug + Hash + Eq; @@ -42,7 +46,8 @@ pub trait Interner: // Kinds of tys type Ty: Ty; - type Tys: Copy + Debug + Hash + Eq + IntoIterator; + type Tys: Tys; + type FnInputTys: Copy + Debug + Hash + Eq + Deref; type ParamTy: Copy + Debug + Hash + Eq; type BoundTy: Copy + Debug + Hash + Eq; type PlaceholderTy: PlaceholderLike; @@ -53,6 +58,8 @@ pub trait Interner: type PolyFnSig: Copy + DebugWithInfcx + Hash + Eq; type AllocId: Copy + Debug + Hash + Eq; type Pat: Copy + Debug + Hash + Eq + DebugWithInfcx; + type Unsafety: Unsafety; + type Abi: Abi; // Kinds of consts type Const: Const; @@ -99,7 +106,7 @@ fn trait_ref_and_own_args_for_alias( self, def_id: Self::DefId, args: Self::GenericArgs, - ) -> (TraitRef, Self::GenericArgsSlice); + ) -> (TraitRef, Self::OwnItemArgs); fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs; diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs index 2a766d0bc09..af4b9eef14b 100644 --- a/compiler/rustc_type_ir/src/ir_print.rs +++ b/compiler/rustc_type_ir/src/ir_print.rs @@ -1,8 +1,8 @@ use std::fmt; use crate::{ - AliasTerm, AliasTy, CoercePredicate, ExistentialProjection, ExistentialTraitRef, Interner, - NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, + AliasTerm, AliasTy, CoercePredicate, ExistentialProjection, ExistentialTraitRef, FnSig, + Interner, NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, }; pub trait IrPrint { @@ -45,6 +45,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { CoercePredicate, AliasTy, AliasTerm, + FnSig, ); define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection); diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index b6c7c2c348c..b0309a622f1 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -497,7 +497,7 @@ pub fn trait_def_id(self, interner: I) -> I::DefId { /// For example, if this is a projection of `::Item<'a>`, /// then this function would return a `T: StreamingIterator` trait reference and /// `['a]` as the own args. - pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef, I::GenericArgsSlice) { + pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef, I::OwnItemArgs) { interner.trait_ref_and_own_args_for_alias(self.def_id, self.args) } diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 672c890f94e..b0158cafa33 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -342,7 +342,7 @@ fn eq(&self, other: &TyKind) -> bool { impl DebugWithInfcx for TyKind { fn fmt>( this: WithInfcx<'_, Infcx, &Self>, - f: &mut core::fmt::Formatter<'_>, + f: &mut fmt::Formatter<'_>, ) -> fmt::Result { match this.data { Bool => write!(f, "bool"), @@ -514,7 +514,7 @@ pub fn trait_def_id(self, interner: I) -> I::DefId { /// For example, if this is a projection of `::Item<'a>`, /// then this function would return a `T: StreamingIterator` trait reference and /// `['a]` as the own args. - pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef, I::GenericArgsSlice) { + pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef, I::OwnItemArgs) { debug_assert_eq!(self.kind(interner), AliasTyKind::Projection); interner.trait_ref_and_own_args_for_alias(self.def_id, self.args) } @@ -561,8 +561,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { impl DebugWithInfcx for AliasTy { fn fmt>( this: WithInfcx<'_, Infcx, &Self>, - f: &mut core::fmt::Formatter<'_>, - ) -> core::fmt::Result { + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result { f.debug_struct("AliasTy") .field("args", &this.map(|data| data.args)) .field("def_id", &this.data.def_id) @@ -952,3 +952,76 @@ pub struct TypeAndMut { pub ty: I::Ty, pub mutbl: Mutability, } + +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Hash(bound = "") +)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +pub struct FnSig { + pub inputs_and_output: I::Tys, + pub c_variadic: bool, + pub unsafety: I::Unsafety, + pub abi: I::Abi, +} + +impl FnSig { + pub fn split_inputs_and_output(self) -> (I::FnInputTys, I::Ty) { + self.inputs_and_output.split_inputs_and_output() + } + + pub fn inputs(self) -> I::FnInputTys { + self.split_inputs_and_output().0 + } + + pub fn output(self) -> I::Ty { + self.split_inputs_and_output().1 + } +} + +impl fmt::Debug for FnSig { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + WithInfcx::with_no_infcx(self).fmt(f) + } +} +impl DebugWithInfcx for FnSig { + fn fmt>( + this: WithInfcx<'_, Infcx, &Self>, + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + let sig = this.data; + let FnSig { inputs_and_output: _, c_variadic, unsafety, abi } = sig; + + write!(f, "{}", unsafety.prefix_str())?; + if !abi.is_rust() { + write!(f, "extern \"{abi:?}\" ")?; + } + + write!(f, "fn(")?; + let (inputs, output) = sig.split_inputs_and_output(); + for (i, ty) in inputs.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + write!(f, "{:?}", &this.wrap(ty))?; + } + if *c_variadic { + if inputs.is_empty() { + write!(f, "...")?; + } else { + write!(f, ", ...")?; + } + } + write!(f, ")")?; + + match output.kind() { + Tuple(list) if list.is_empty() => Ok(()), + _ => write!(f, " -> {:?}", &this.wrap(sig.output())), + } + } +} From d3e510eb9dcb81059d5bc31cbbf212b8d96537cf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 7 May 2024 21:54:19 -0400 Subject: [PATCH 5/5] Don't ICE because recomputing overflow goals during find_best_leaf_obligation causes inference side-effects --- .../src/solve/fulfill.rs | 105 +++++++++++------- .../coherence-fulfill-overflow.stderr | 6 +- .../fixpoint-exponential-growth.stderr | 9 +- .../double-cycle-inductive-coinductive.stderr | 36 +----- .../cycles/inductive-fixpoint-hang.stderr | 12 +- .../cycles/inductive-not-on-stack.rs | 2 +- .../cycles/inductive-not-on-stack.stderr | 41 +------ .../next-solver/cycles/mixed-cycles-1.rs | 2 +- .../next-solver/cycles/mixed-cycles-1.stderr | 39 +------ .../next-solver/cycles/mixed-cycles-2.rs | 2 +- .../next-solver/cycles/mixed-cycles-2.stderr | 25 +---- .../next-solver/diagnostics/ambiguous-fail.rs | 21 ++++ .../diagnostics/ambiguous-fail.stderr | 12 ++ .../next-solver/diagnostics/ambiguous-pass.rs | 21 ++++ .../diagnostics/ambiguous-pass.stderr | 12 ++ .../overflow/exponential-trait-goals.rs | 2 +- .../overflow/exponential-trait-goals.stderr | 9 +- .../next-solver/overflow/global-cache.stderr | 9 -- 18 files changed, 145 insertions(+), 220 deletions(-) create mode 100644 tests/ui/traits/next-solver/diagnostics/ambiguous-fail.rs create mode 100644 tests/ui/traits/next-solver/diagnostics/ambiguous-fail.stderr create mode 100644 tests/ui/traits/next-solver/diagnostics/ambiguous-pass.rs create mode 100644 tests/ui/traits/next-solver/diagnostics/ambiguous-pass.stderr diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 3323f1bbf39..3379c1d51a8 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -244,16 +244,23 @@ fn fulfillment_error_for_no_solution<'tcx>( fn fulfillment_error_for_stalled<'tcx>( infcx: &InferCtxt<'tcx>, - obligation: PredicateObligation<'tcx>, + root_obligation: PredicateObligation<'tcx>, ) -> FulfillmentError<'tcx> { - let code = infcx.probe(|_| { - match infcx.evaluate_root_goal(obligation.clone().into(), GenerateProofTree::Never).0 { + let (code, refine_obligation) = infcx.probe(|_| { + match infcx.evaluate_root_goal(root_obligation.clone().into(), GenerateProofTree::Never).0 { Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => { - FulfillmentErrorCode::Ambiguity { overflow: None } - } - Ok((_, Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }))) => { - FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } + (FulfillmentErrorCode::Ambiguity { overflow: None }, true) } + Ok((_, Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }))) => ( + FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) }, + // Don't look into overflows because we treat overflows weirdly anyways. + // In `instantiate_response_discarding_overflow` we set `has_changed = false`, + // recomputing the goal again during `find_best_leaf_obligation` may apply + // inference guidance that makes other goals go from ambig -> pass, for example. + // + // FIXME: We should probably just look into overflows here. + false, + ), Ok((_, Certainty::Yes)) => { bug!("did not expect successful goal when collecting ambiguity errors") } @@ -264,9 +271,13 @@ fn fulfillment_error_for_stalled<'tcx>( }); FulfillmentError { - obligation: find_best_leaf_obligation(infcx, &obligation, true), + obligation: if refine_obligation { + find_best_leaf_obligation(infcx, &root_obligation, true) + } else { + root_obligation.clone() + }, code, - root_obligation: obligation, + root_obligation, } } @@ -302,41 +313,50 @@ fn with_derived_obligation( res } - /// Filter out the candidates that aren't either error or ambiguous (depending - /// on what we are looking for), and also throw out candidates that have no - /// failing WC (or higher-ranked obligations, for which there should only be - /// one candidate anyways -- but I digress). This most likely means that the - /// goal just didn't unify at all, e.g. a param candidate with an alias in it. + /// Filter out the candidates that aren't interesting to visit for the + /// purposes of reporting errors. For ambiguities, we only consider + /// candidates that may hold. For errors, we only consider candidates that + /// *don't* hold and which have impl-where clauses that also don't hold. fn non_trivial_candidates<'a>( &self, goal: &'a InspectGoal<'a, 'tcx>, ) -> Vec> { - let mut candidates = goal - .candidates() - .into_iter() - .filter(|candidate| match self.consider_ambiguities { - true => matches!(candidate.result(), Ok(Certainty::Maybe(_))), - false => matches!(candidate.result(), Err(_)), - }) - .collect::>(); - - // If we have >1 candidate, one may still be due to "boring" reasons, like - // an alias-relate that failed to hold when deeply evaluated. We really - // don't care about reasons like this. - if candidates.len() > 1 { - candidates.retain(|candidate| { - goal.infcx().probe(|_| { - candidate.instantiate_nested_goals(self.span()).iter().any(|nested_goal| { - matches!( - nested_goal.source(), - GoalSource::ImplWhereBound | GoalSource::InstantiateHigherRanked - ) && match self.consider_ambiguities { - true => matches!(nested_goal.result(), Ok(Certainty::Maybe(_))), - false => matches!(nested_goal.result(), Err(_)), - } - }) - }) - }); + let mut candidates = goal.candidates(); + match self.consider_ambiguities { + true => { + // If we have an ambiguous obligation, we must consider *all* candidates + // that hold, or else we may guide inference causing other goals to go + // from ambig -> pass/fail. + candidates.retain(|candidate| candidate.result().is_ok()); + } + false => { + // If we have >1 candidate, one may still be due to "boring" reasons, like + // an alias-relate that failed to hold when deeply evaluated. We really + // don't care about reasons like this. + if candidates.len() > 1 { + candidates.retain(|candidate| { + goal.infcx().probe(|_| { + candidate.instantiate_nested_goals(self.span()).iter().any( + |nested_goal| { + matches!( + nested_goal.source(), + GoalSource::ImplWhereBound + | GoalSource::InstantiateHigherRanked + ) && match self.consider_ambiguities { + true => { + matches!( + nested_goal.result(), + Ok(Certainty::Maybe(MaybeCause::Ambiguity)) + ) + } + false => matches!(nested_goal.result(), Err(_)), + } + }, + ) + }) + }); + } + } } candidates @@ -401,7 +421,10 @@ fn visit_goal(&mut self, goal: &super::inspect::InspectGoal<'_, 'tcx>) -> Self:: // Skip nested goals that aren't the *reason* for our goal's failure. match self.consider_ambiguities { - true if matches!(nested_goal.result(), Ok(Certainty::Maybe(_))) => {} + true if matches!( + nested_goal.result(), + Ok(Certainty::Maybe(MaybeCause::Ambiguity)) + ) => {} false if matches!(nested_goal.result(), Err(_)) => {} _ => continue, } diff --git a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr index 6e68646fbe4..57cba790b55 100644 --- a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr +++ b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr @@ -1,12 +1,12 @@ -error[E0119]: conflicting implementations of trait `Trait` for type `W>>>>>>>>>>>>>>>>>>>>>` +error[E0119]: conflicting implementations of trait `Trait` for type `W>>>>>>>>>>>>>>>>>>>>` --> $DIR/coherence-fulfill-overflow.rs:12:1 | LL | impl Trait for W {} | ------------------------------------- first implementation here LL | impl Trait for T {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W>>>>>>>>>>>>>>>>>>>>>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W>>>>>>>>>>>>>>>>>>>>` | - = note: overflow evaluating the requirement `W>>>: TwoW` + = note: overflow evaluating the requirement `W>>>>>>>>>>>>>>>>>>>>: TwoW` = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`coherence_fulfill_overflow`) error: aborting due to 1 previous error diff --git a/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr b/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr index df25150c21f..8d7d8cee08a 100644 --- a/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr +++ b/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr @@ -1,16 +1,9 @@ -error[E0275]: overflow evaluating the requirement `_: Sized` +error[E0275]: overflow evaluating the requirement `W<_>: Trait` --> $DIR/fixpoint-exponential-growth.rs:33:13 | LL | impls::>(); | ^^^^ | -note: required for `W<(W<_>, W<_>)>` to implement `Trait` - --> $DIR/fixpoint-exponential-growth.rs:23:12 - | -LL | impl Trait for W<(W, W)> - | - ^^^^^ ^^^^^^^^^^^^^^^ - | | - | unsatisfied trait bound introduced here note: required by a bound in `impls` --> $DIR/fixpoint-exponential-growth.rs:30:13 | diff --git a/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr b/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr index 86c71ad92ff..7cedb4d36c9 100644 --- a/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr +++ b/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr @@ -1,53 +1,21 @@ -error[E0275]: overflow evaluating the requirement `(): Inductive` +error[E0275]: overflow evaluating the requirement `(): Trait` --> $DIR/double-cycle-inductive-coinductive.rs:32:19 | LL | impls_trait::<()>(); | ^^ | -note: required for `()` to implement `Trait` - --> $DIR/double-cycle-inductive-coinductive.rs:9:34 - | -LL | impl Trait for T {} - | --------- ^^^^^ ^ - | | - | unsatisfied trait bound introduced here -note: required for `()` to implement `Inductive` - --> $DIR/double-cycle-inductive-coinductive.rs:12:16 - | -LL | impl Inductive for T {} - | ----- ^^^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here - = note: 7 redundant requirements hidden - = note: required for `()` to implement `Trait` note: required by a bound in `impls_trait` --> $DIR/double-cycle-inductive-coinductive.rs:17:19 | LL | fn impls_trait() {} | ^^^^^ required by this bound in `impls_trait` -error[E0275]: overflow evaluating the requirement `(): CoinductiveRev` +error[E0275]: overflow evaluating the requirement `(): TraitRev` --> $DIR/double-cycle-inductive-coinductive.rs:35:23 | LL | impls_trait_rev::<()>(); | ^^ | -note: required for `()` to implement `TraitRev` - --> $DIR/double-cycle-inductive-coinductive.rs:21:40 - | -LL | impl TraitRev for T {} - | -------------- ^^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here -note: required for `()` to implement `CoinductiveRev` - --> $DIR/double-cycle-inductive-coinductive.rs:27:19 - | -LL | impl CoinductiveRev for T {} - | -------- ^^^^^^^^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here - = note: 7 redundant requirements hidden - = note: required for `()` to implement `TraitRev` note: required by a bound in `impls_trait_rev` --> $DIR/double-cycle-inductive-coinductive.rs:29:23 | diff --git a/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr b/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr index ea46c0fea97..a2a5c028cf8 100644 --- a/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr +++ b/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr @@ -1,19 +1,9 @@ -error[E0275]: overflow evaluating the requirement `W>: Trait` +error[E0275]: overflow evaluating the requirement `W<_>: Trait` --> $DIR/inductive-fixpoint-hang.rs:31:19 | LL | impls_trait::>(); | ^^^^ | -note: required for `W>>` to implement `Trait` - --> $DIR/inductive-fixpoint-hang.rs:22:17 - | -LL | impl Trait for W> - | ^^^^^ ^^^^^^^ -LL | where -LL | W: Trait, - | ----- unsatisfied trait bound introduced here - = note: 8 redundant requirements hidden - = note: required for `W>>>>>>>>>>` to implement `Trait` note: required by a bound in `impls_trait` --> $DIR/inductive-fixpoint-hang.rs:28:19 | diff --git a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs index 9d0ea51b1b2..78683372580 100644 --- a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs +++ b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs @@ -39,7 +39,7 @@ fn impls_ar() {} fn main() { impls_a::<()>(); - //~^ ERROR overflow evaluating the requirement `(): B` + //~^ ERROR overflow evaluating the requirement `(): A` impls_ar::<()>(); //~^ ERROR overflow evaluating the requirement `(): AR` diff --git a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr index fe02d3c407c..e9cc6bc6c81 100644 --- a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr +++ b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr @@ -1,25 +1,9 @@ -error[E0275]: overflow evaluating the requirement `(): B` +error[E0275]: overflow evaluating the requirement `(): A` --> $DIR/inductive-not-on-stack.rs:41:15 | LL | impls_a::<()>(); | ^^ | -note: required for `()` to implement `A` - --> $DIR/inductive-not-on-stack.rs:21:16 - | -LL | impl A for T {} - | - ^ ^ - | | - | unsatisfied trait bound introduced here -note: required for `()` to implement `B` - --> $DIR/inductive-not-on-stack.rs:22:12 - | -LL | impl B for T {} - | - ^ ^ - | | - | unsatisfied trait bound introduced here - = note: 7 redundant requirements hidden - = note: required for `()` to implement `A` note: required by a bound in `impls_a` --> $DIR/inductive-not-on-stack.rs:25:15 | @@ -32,29 +16,6 @@ error[E0275]: overflow evaluating the requirement `(): AR` LL | impls_ar::<()>(); | ^^ | -note: required for `()` to implement `BR` - --> $DIR/inductive-not-on-stack.rs:35:13 - | -LL | impl BR for T {} - | -- ^^ ^ - | | - | unsatisfied trait bound introduced here -note: required for `()` to implement `CR` - --> $DIR/inductive-not-on-stack.rs:36:13 - | -LL | impl CR for T {} - | -- ^^ ^ - | | - | unsatisfied trait bound introduced here -note: required for `()` to implement `AR` - --> $DIR/inductive-not-on-stack.rs:34:18 - | -LL | impl AR for T {} - | -- ^^ ^ - | | - | unsatisfied trait bound introduced here - = note: 6 redundant requirements hidden - = note: required for `()` to implement `AR` note: required by a bound in `impls_ar` --> $DIR/inductive-not-on-stack.rs:38:16 | diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs index b90a354be1b..6d75d241864 100644 --- a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs +++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs @@ -35,5 +35,5 @@ fn impls_a() {} fn main() { impls_a::<()>(); - //~^ ERROR overflow evaluating the requirement `(): CInd` + //~^ ERROR overflow evaluating the requirement `(): A` } diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr index 03e61dbf99c..17544eb1da5 100644 --- a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr +++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr @@ -1,46 +1,9 @@ -error[E0275]: overflow evaluating the requirement `(): CInd` +error[E0275]: overflow evaluating the requirement `(): A` --> $DIR/mixed-cycles-1.rs:37:15 | LL | impls_a::<()>(); | ^^ | -note: required for `()` to implement `B` - --> $DIR/mixed-cycles-1.rs:31:28 - | -LL | impl B for T {} - | ---- ^ ^ - | | - | unsatisfied trait bound introduced here -note: required for `()` to implement `C` - --> $DIR/mixed-cycles-1.rs:32:25 - | -LL | impl C for T {} - | - ^ ^ - | | - | unsatisfied trait bound introduced here -note: required for `()` to implement `CInd` - --> $DIR/mixed-cycles-1.rs:28:21 - | -LL | impl CInd for T {} - | - ^^^^ ^ - | | - | unsatisfied trait bound introduced here - = note: 4 redundant requirements hidden - = note: required for `()` to implement `B` -note: required for `()` to implement `BInd` - --> $DIR/mixed-cycles-1.rs:23:21 - | -LL | impl BInd for T {} - | - ^^^^ ^ - | | - | unsatisfied trait bound introduced here -note: required for `()` to implement `A` - --> $DIR/mixed-cycles-1.rs:30:28 - | -LL | impl A for T {} - | ---- ^ ^ - | | - | unsatisfied trait bound introduced here note: required by a bound in `impls_a` --> $DIR/mixed-cycles-1.rs:34:15 | diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs index a3ffcaafb37..c939a6e5ef2 100644 --- a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs +++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs @@ -28,5 +28,5 @@ fn impls_a() {} fn main() { impls_a::<()>(); - //~^ ERROR overflow evaluating the requirement `(): BInd` + //~^ ERROR overflow evaluating the requirement `(): A` } diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr index 892426abe82..a9be1016c74 100644 --- a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr +++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr @@ -1,32 +1,9 @@ -error[E0275]: overflow evaluating the requirement `(): BInd` +error[E0275]: overflow evaluating the requirement `(): A` --> $DIR/mixed-cycles-2.rs:30:15 | LL | impls_a::<()>(); | ^^ | -note: required for `()` to implement `B` - --> $DIR/mixed-cycles-2.rs:25:24 - | -LL | impl B for T {} - | ---- ^ ^ - | | - | unsatisfied trait bound introduced here -note: required for `()` to implement `BInd` - --> $DIR/mixed-cycles-2.rs:22:21 - | -LL | impl BInd for T {} - | - ^^^^ ^ - | | - | unsatisfied trait bound introduced here - = note: 6 redundant requirements hidden - = note: required for `()` to implement `BInd` -note: required for `()` to implement `A` - --> $DIR/mixed-cycles-2.rs:24:28 - | -LL | impl A for T {} - | ---- ^ ^ - | | - | unsatisfied trait bound introduced here note: required by a bound in `impls_a` --> $DIR/mixed-cycles-2.rs:27:15 | diff --git a/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.rs b/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.rs new file mode 100644 index 00000000000..4094ab84166 --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -Znext-solver + +trait Trait { + type Assoc; +} + +struct W(*mut T); +impl Trait for W> +where + W: Trait, +{ + type Assoc = (); +} + +trait NoOverlap {} +impl NoOverlap for T {} + +impl> NoOverlap for W {} +//~^ ERROR conflicting implementations of trait `NoOverlap` for type `W<_>` + +fn main() {} diff --git a/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.stderr b/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.stderr new file mode 100644 index 00000000000..42be1960563 --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `NoOverlap` for type `W<_>` + --> $DIR/ambiguous-fail.rs:18:1 + | +LL | impl NoOverlap for T {} + | ------------------------------ first implementation here +LL | +LL | impl> NoOverlap for W {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<_>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.rs b/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.rs new file mode 100644 index 00000000000..2d40ba37a89 --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -Znext-solver + +trait Trait { + type Assoc; +} + +struct W(*mut T); +impl Trait for W> +where + W: Trait, +{ + type Assoc = (); +} + +trait NoOverlap {} +impl NoOverlap for T {} + +impl> NoOverlap for W {} +//~^ ERROR conflicting implementations of trait `NoOverlap` for type `W<_>` + +fn main() {} diff --git a/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.stderr b/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.stderr new file mode 100644 index 00000000000..5c77fc71e55 --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `NoOverlap` for type `W<_>` + --> $DIR/ambiguous-pass.rs:18:1 + | +LL | impl NoOverlap for T {} + | ------------------------------ first implementation here +LL | +LL | impl> NoOverlap for W {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<_>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/next-solver/overflow/exponential-trait-goals.rs b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.rs index 052d803765d..186d0e8be56 100644 --- a/tests/ui/traits/next-solver/overflow/exponential-trait-goals.rs +++ b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.rs @@ -15,5 +15,5 @@ fn impls() {} fn main() { impls::>(); - //~^ ERROR overflow evaluating the requirement `_: Sized` + //~^ ERROR overflow evaluating the requirement `W<_>: Trait` } diff --git a/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr index 6583cae8bb9..b032ae3e740 100644 --- a/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr +++ b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr @@ -1,16 +1,9 @@ -error[E0275]: overflow evaluating the requirement `_: Sized` +error[E0275]: overflow evaluating the requirement `W<_>: Trait` --> $DIR/exponential-trait-goals.rs:17:13 | LL | impls::>(); | ^^^^ | -note: required for `W<(W<_>, W<_>)>` to implement `Trait` - --> $DIR/exponential-trait-goals.rs:7:12 - | -LL | impl Trait for W<(W, W)> - | - ^^^^^ ^^^^^^^^^^^^^^^ - | | - | unsatisfied trait bound introduced here note: required by a bound in `impls` --> $DIR/exponential-trait-goals.rs:14:13 | diff --git a/tests/ui/traits/next-solver/overflow/global-cache.stderr b/tests/ui/traits/next-solver/overflow/global-cache.stderr index 9e467721e83..67616619384 100644 --- a/tests/ui/traits/next-solver/overflow/global-cache.stderr +++ b/tests/ui/traits/next-solver/overflow/global-cache.stderr @@ -5,15 +5,6 @@ LL | impls_trait::>>>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "18"]` attribute to your crate (`global_cache`) -note: required for `Inc>>>>>>>>>>` to implement `Trait` - --> $DIR/global-cache.rs:12:16 - | -LL | impl Trait for Inc {} - | ----- ^^^^^ ^^^^^^ - | | - | unsatisfied trait bound introduced here - = note: 5 redundant requirements hidden - = note: required for `Inc>>>>>>>>>>>>>>>` to implement `Trait` note: required by a bound in `impls_trait` --> $DIR/global-cache.rs:15:19 |