From f2de5fb2ae0f69d403a06ff4f963e63d95406591 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Sun, 12 May 2024 14:00:09 -0400 Subject: [PATCH 01/14] rewrite issue-14500 to rmake --- src/tools/run-make-support/src/rustc.rs | 14 +++++++++ .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/issue-14500/Makefile | 15 --------- tests/run-make/issue-14500/rmake.rs | 31 +++++++++++++++++++ 4 files changed, 45 insertions(+), 16 deletions(-) delete mode 100644 tests/run-make/issue-14500/Makefile create mode 100644 tests/run-make/issue-14500/rmake.rs diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index de773d688ef..c92e9f9b11f 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -150,6 +150,20 @@ impl Rustc { self } + /// Pass a codegen option. + pub fn codegen_option(&mut self, option: &str) -> &mut Self { + self.cmd.arg("-C"); + self.cmd.arg(option); + self + } + + /// Add a directory to the library search path. + pub fn library_search_path>(&mut self, path: P) -> &mut Self { + self.cmd.arg("-L"); + self.cmd.arg(path.as_ref()); + self + } + /// Specify the edition year. pub fn edition(&mut self, edition: &str) -> &mut Self { self.cmd.arg("--edition"); diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index e87950b36d9..a358bc89e13 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -99,7 +99,6 @@ run-make/issue-107094/Makefile run-make/issue-10971-temps-dir/Makefile run-make/issue-109934-lto-debuginfo/Makefile run-make/issue-11908/Makefile -run-make/issue-14500/Makefile run-make/issue-14698/Makefile run-make/issue-15460/Makefile run-make/issue-18943/Makefile diff --git a/tests/run-make/issue-14500/Makefile b/tests/run-make/issue-14500/Makefile deleted file mode 100644 index eeab48de3b9..00000000000 --- a/tests/run-make/issue-14500/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -include ../tools.mk - -# ignore-cross-compile - -# Test to make sure that reachable extern fns are always available in final -# productcs, including when LTO is used. In this test, the `foo` crate has a -# reahable symbol, and is a dependency of the `bar` crate. When the `bar` crate -# is compiled with LTO, it shouldn't strip the symbol from `foo`, and that's the -# only way that `foo.c` will successfully compile. - -all: - $(RUSTC) foo.rs --crate-type=rlib - $(RUSTC) bar.rs --crate-type=staticlib -C lto -L. -o $(TMPDIR)/libbar.a - $(CC) foo.c $(TMPDIR)/libbar.a $(EXTRACFLAGS) $(call OUT_EXE,foo) - $(call RUN,foo) diff --git a/tests/run-make/issue-14500/rmake.rs b/tests/run-make/issue-14500/rmake.rs new file mode 100644 index 00000000000..58c6bc9ebb3 --- /dev/null +++ b/tests/run-make/issue-14500/rmake.rs @@ -0,0 +1,31 @@ +// Test to make sure that reachable extern fns are always available in final +// productcs, including when LTO is used. + +// In this test, the `foo` crate has a reahable symbol, +// and is a dependency of the `bar` crate. When the `bar` crate +// is compiled with LTO, it shouldn't strip the symbol from `foo`, and that's the +// only way that `foo.c` will successfully compile. +// See https://github.com/rust-lang/rust/issues/14500 + +//@ ignore-cross-compile + +use run_make_support::{cc, extra_c_flags, run, rustc}; + +fn main() { + let libbar_path = tmp_dir().join("libbar.a"); + rustc().input("foo.rs") + .crate_type("rlib") + .run(); + rustc().input("bar.rs") + .static_lib("staticlib") + .codegen_option("lto") + .library_search_path(".") + .output(&libbar_path) + .run(); + cc().input("foo.c") + .input(libbar_path) + .args(&extra_c_flags()) + .out_exe("foo") + .run(); + run("foo"); +} From a1b5ea0cc220d11b831f49a92c2e37b31ae928d3 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Sun, 12 May 2024 14:13:02 -0400 Subject: [PATCH 02/14] make tidy happy --- tests/run-make/issue-14500/rmake.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/tests/run-make/issue-14500/rmake.rs b/tests/run-make/issue-14500/rmake.rs index 58c6bc9ebb3..956d66ba88f 100644 --- a/tests/run-make/issue-14500/rmake.rs +++ b/tests/run-make/issue-14500/rmake.rs @@ -13,19 +13,14 @@ use run_make_support::{cc, extra_c_flags, run, rustc}; fn main() { let libbar_path = tmp_dir().join("libbar.a"); - rustc().input("foo.rs") - .crate_type("rlib") - .run(); - rustc().input("bar.rs") + rustc().input("foo.rs").crate_type("rlib").run(); + rustc() + .input("bar.rs") .static_lib("staticlib") .codegen_option("lto") .library_search_path(".") .output(&libbar_path) .run(); - cc().input("foo.c") - .input(libbar_path) - .args(&extra_c_flags()) - .out_exe("foo") - .run(); + cc().input("foo.c").input(libbar_path).args(&extra_c_flags()).out_exe("foo").run(); run("foo"); } From 71fd2cf5b44441c91673e90414d1e445d8de1922 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Sun, 12 May 2024 15:02:22 -0400 Subject: [PATCH 03/14] fix function call and import --- tests/run-make/issue-14500/rmake.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-make/issue-14500/rmake.rs b/tests/run-make/issue-14500/rmake.rs index 956d66ba88f..58f632e5909 100644 --- a/tests/run-make/issue-14500/rmake.rs +++ b/tests/run-make/issue-14500/rmake.rs @@ -9,14 +9,14 @@ //@ ignore-cross-compile -use run_make_support::{cc, extra_c_flags, run, rustc}; +use run_make_support::{cc, extra_c_flags, run, rustc, tmp_dir}; fn main() { let libbar_path = tmp_dir().join("libbar.a"); rustc().input("foo.rs").crate_type("rlib").run(); rustc() .input("bar.rs") - .static_lib("staticlib") + .crate_type("staticlib") .codegen_option("lto") .library_search_path(".") .output(&libbar_path) From 2e4c90c3f7c11c745a5d787809ad36c49970a25b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 13 May 2024 22:05:11 -0400 Subject: [PATCH 04/14] Don't do post-method-probe error reporting steps if we're in a suggestion --- compiler/rustc_hir_typeck/src/demand.rs | 4 ++-- compiler/rustc_hir_typeck/src/expr.rs | 9 ++++++-- .../src/fn_ctxt/suggestions.rs | 3 ++- compiler/rustc_hir_typeck/src/method/mod.rs | 4 ++-- compiler/rustc_hir_typeck/src/method/probe.rs | 23 ++++++++++++++++++- .../rustc_hir_typeck/src/method/suggest.rs | 3 ++- 6 files changed, 37 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 706f6f875bf..6da5adc7a6e 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -938,14 +938,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - pub fn get_conversion_methods( + pub fn get_conversion_methods_for_diagnostic( &self, span: Span, expected: Ty<'tcx>, checked_ty: Ty<'tcx>, hir_id: hir::HirId, ) -> Vec { - let methods = self.probe_for_return_type( + let methods = self.probe_for_return_type_for_diagnostic( span, probe::Mode::MethodCall, expected, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index f283c013805..5a9eab1ffea 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2414,7 +2414,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let guar = if field.name == kw::Empty { self.dcx().span_delayed_bug(field.span, "field name with no name") - } else if self.method_exists(field, base_ty, expr.hir_id, expected.only_has_type(self)) { + } else if self.method_exists_for_diagnostic( + field, + base_ty, + expr.hir_id, + expected.only_has_type(self), + ) { self.ban_take_value_of_method(expr, base_ty, field) } else if !base_ty.is_primitive_ty() { self.ban_nonexisting_field(field, base, expr, base_ty) @@ -2600,7 +2605,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut err = self.private_field_err(field, base_did); // Also check if an accessible method exists, which is often what is meant. - if self.method_exists(field, expr_t, expr.hir_id, return_ty) + if self.method_exists_for_diagnostic(field, expr_t, expr.hir_id, return_ty) && !self.expr_in_place(expr.hir_id) { self.suggest_method_call( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 11f288391c3..fe0dd4e393f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -290,7 +290,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, ) -> bool { let expr = expr.peel_blocks(); - let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id); + let methods = + self.get_conversion_methods_for_diagnostic(expr.span, expected, found, expr.hir_id); if let Some((suggestion, msg, applicability, verbose, annotation)) = self.suggest_deref_or_ref(expr, found, expected) diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index f82182fa058..a40fa600c19 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -91,7 +91,7 @@ pub enum CandidateSource { impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Determines whether the type `self_ty` supports a visible method named `method_name` or not. #[instrument(level = "debug", skip(self))] - pub fn method_exists( + pub fn method_exists_for_diagnostic( &self, method_name: Ident, self_ty: Ty<'tcx>, @@ -102,7 +102,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { probe::Mode::MethodCall, method_name, return_type, - IsSuggestion(false), + IsSuggestion(true), self_ty, call_expr_id, ProbeScope::TraitsInScope, diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 81e179c9090..6cfdacf6a24 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -90,6 +90,11 @@ pub(crate) struct ProbeContext<'a, 'tcx> { >, scope_expr_id: HirId, + + /// Is this probe being done for a diagnostic? This will skip some error reporting + /// machinery, since we don't particularly care about, for example, similarly named + /// candidates if we're *reporting* similarly named candidates. + is_suggestion: IsSuggestion, } impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> { @@ -220,7 +225,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// would use to decide if a method is a plausible fit for /// ambiguity purposes). #[instrument(level = "debug", skip(self, candidate_filter))] - pub fn probe_for_return_type( + pub fn probe_for_return_type_for_diagnostic( &self, span: Span, mode: Mode, @@ -459,6 +464,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &orig_values, steps.steps, scope_expr_id, + is_suggestion, ); probe_cx.assemble_inherent_candidates(); @@ -553,6 +559,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { orig_steps_var_values: &'a OriginalQueryValues<'tcx>, steps: &'tcx [CandidateStep<'tcx>], scope_expr_id: HirId, + is_suggestion: IsSuggestion, ) -> ProbeContext<'a, 'tcx> { ProbeContext { fcx, @@ -570,6 +577,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { static_candidates: RefCell::new(Vec::new()), unsatisfied_predicates: RefCell::new(Vec::new()), scope_expr_id, + is_suggestion, } } @@ -944,6 +952,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { return r; } + // If it's a `lookup_probe_for_diagnostic`, then quit early. No need to + // probe for other candidates. + if self.is_suggestion.0 { + return Err(MethodError::NoMatch(NoMatchData { + static_candidates: vec![], + unsatisfied_predicates: vec![], + out_of_scope_traits: vec![], + similar_candidate: None, + mode: self.mode, + })); + } + debug!("pick: actual search failed, assemble diagnostics"); let static_candidates = std::mem::take(self.static_candidates.get_mut()); @@ -1631,6 +1651,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.orig_steps_var_values, self.steps, self.scope_expr_id, + IsSuggestion(true), ); pcx.allow_similar_names = true; pcx.assemble_inherent_candidates(); diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index d50e9943384..c1cbe05f6bd 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2814,7 +2814,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(output_ty) => self.resolve_vars_if_possible(output_ty), _ => return, }; - let method_exists = self.method_exists(item_name, output_ty, call.hir_id, return_type); + let method_exists = + self.method_exists_for_diagnostic(item_name, output_ty, call.hir_id, return_type); debug!("suggest_await_before_method: is_method_exist={}", method_exists); if method_exists { err.span_suggestion_verbose( From 1ad28a6f534d7673664e8f26c632bc71490c33a6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 13 May 2024 12:40:08 -0400 Subject: [PATCH 05/14] Uplift AliasTy --- compiler/rustc_errors/src/diagnostic_impls.rs | 6 + compiler/rustc_middle/src/ty/consts.rs | 18 +- compiler/rustc_middle/src/ty/consts/kind.rs | 30 +- compiler/rustc_middle/src/ty/context.rs | 76 +++- compiler/rustc_middle/src/ty/mod.rs | 16 +- compiler/rustc_middle/src/ty/predicate.rs | 1 + compiler/rustc_middle/src/ty/print/pretty.rs | 54 +-- .../rustc_middle/src/ty/structural_impls.rs | 36 +- compiler/rustc_middle/src/ty/sty.rs | 388 +----------------- compiler/rustc_type_ir/src/const_kind.rs | 41 ++ compiler/rustc_type_ir/src/inherent.rs | 29 +- compiler/rustc_type_ir/src/interner.rs | 25 +- compiler/rustc_type_ir/src/ir_print.rs | 6 +- compiler/rustc_type_ir/src/predicate.rs | 234 +++++++++-- compiler/rustc_type_ir/src/ty_kind.rs | 158 ++++++- 15 files changed, 584 insertions(+), 534 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 2cc0167dbaa..d9add1c9b3b 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -106,6 +106,12 @@ impl IntoDiagArg for rustc_type_ir::ExistentialTrait } } +impl IntoDiagArg for rustc_type_ir::UnevaluatedConst { + 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_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 329d5f34a21..27a4abaa0b6 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -7,8 +7,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; -use rustc_type_ir::ConstKind as IrConstKind; -use rustc_type_ir::{TypeFlags, WithCachedTypeInfo}; +use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo}; mod int; mod kind; @@ -20,7 +19,8 @@ use rustc_span::Span; use rustc_span::DUMMY_SP; pub use valtree::*; -pub type ConstKind<'tcx> = IrConstKind>; +pub type ConstKind<'tcx> = ir::ConstKind>; +pub type UnevaluatedConst<'tcx> = ir::UnevaluatedConst>; #[cfg(target_pointer_width = "64")] rustc_data_structures::static_assert_size!(ConstKind<'_>, 32); @@ -184,9 +184,21 @@ impl<'tcx> rustc_type_ir::inherent::Const> for Const<'tcx> { Const::new_bound(tcx, debruijn, var, ty) } + fn new_unevaluated( + interner: TyCtxt<'tcx>, + uv: ty::UnevaluatedConst<'tcx>, + ty: Ty<'tcx>, + ) -> Self { + Const::new_unevaluated(interner, uv, ty) + } + fn ty(self) -> Ty<'tcx> { self.ty() } + + fn into_term(self) -> ty::Term<'tcx> { + self.into() + } } impl<'tcx> Const<'tcx> { diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 7e49b0ac915..d7ae050ed4d 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -1,30 +1,15 @@ use super::Const; use crate::mir; use crate::ty::abstract_const::CastKind; -use crate::ty::GenericArgsRef; use crate::ty::{self, visit::TypeVisitableExt as _, List, Ty, TyCtxt}; -use rustc_hir::def_id::DefId; -use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; +use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; -/// An unevaluated (potentially generic) constant used in the type-system. -#[derive(Copy, Clone, Eq, PartialEq, TyEncodable, TyDecodable)] -#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)] -pub struct UnevaluatedConst<'tcx> { - pub def: DefId, - pub args: GenericArgsRef<'tcx>, -} - -impl rustc_errors::IntoDiagArg for UnevaluatedConst<'_> { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { - format!("{self:?}").into_diag_arg() - } -} - -impl<'tcx> UnevaluatedConst<'tcx> { +#[extension(pub(crate) trait UnevaluatedConstEvalExt<'tcx>)] +impl<'tcx> ty::UnevaluatedConst<'tcx> { /// FIXME(RalfJung): I cannot explain what this does or why it makes sense, but not doing this /// hurts performance. #[inline] - pub(crate) fn prepare_for_eval( + fn prepare_for_eval( self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -55,13 +40,6 @@ impl<'tcx> UnevaluatedConst<'tcx> { } } -impl<'tcx> UnevaluatedConst<'tcx> { - #[inline] - pub fn new(def: DefId, args: GenericArgsRef<'tcx>) -> UnevaluatedConst<'tcx> { - UnevaluatedConst { def, args } - } -} - #[derive(Copy, Clone, Eq, PartialEq, Hash)] #[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)] pub enum Expr<'tcx> { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e831db1a41b..d7e185dd5e1 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -76,6 +76,7 @@ use rustc_type_ir::TyKind::*; use rustc_type_ir::WithCachedTypeInfo; use rustc_type_ir::{CollectAndApply, Interner, TypeFlags}; +use std::assert_matches::assert_matches; use std::borrow::Borrow; use std::cmp::Ordering; use std::fmt; @@ -91,67 +92,124 @@ 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 GenericArg = ty::GenericArg<'tcx>; - type Term = ty::Term<'tcx>; + type Term = ty::Term<'tcx>; type Binder>> = Binder<'tcx, T>; type BoundVars = &'tcx List; type BoundVar = ty::BoundVariableKind; - type CanonicalVars = CanonicalVarInfos<'tcx>; + type CanonicalVars = CanonicalVarInfos<'tcx>; type Ty = Ty<'tcx>; type Tys = &'tcx List>; - type AliasTy = ty::AliasTy<'tcx>; type ParamTy = ParamTy; type BoundTy = ty::BoundTy; type PlaceholderTy = ty::PlaceholderType; - type ErrorGuaranteed = ErrorGuaranteed; + type ErrorGuaranteed = ErrorGuaranteed; type BoundExistentialPredicates = &'tcx List>; type PolyFnSig = PolyFnSig<'tcx>; type AllocId = crate::mir::interpret::AllocId; - type Pat = Pattern<'tcx>; + type Pat = Pattern<'tcx>; 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 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 PlaceholderRegion = ty::PlaceholderRegion; type Predicate = Predicate<'tcx>; type TraitPredicate = ty::TraitPredicate<'tcx>; type RegionOutlivesPredicate = ty::RegionOutlivesPredicate<'tcx>; type TypeOutlivesPredicate = ty::TypeOutlivesPredicate<'tcx>; type ProjectionPredicate = ty::ProjectionPredicate<'tcx>; - type AliasTerm = ty::AliasTerm<'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>; + type Clauses = ty::Clauses<'tcx>; fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo]) -> Self::CanonicalVars { self.mk_canonical_var_infos(infos) } type GenericsOf = &'tcx ty::Generics; + fn generics_of(self, def_id: DefId) -> &'tcx ty::Generics { self.generics_of(def_id) } + fn type_of_instantiated(self, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> Ty<'tcx> { + self.type_of(def_id).instantiate(self, args) + } + + fn alias_ty_kind(self, alias: ty::AliasTy<'tcx>) -> ty::AliasTyKind { + match self.def_kind(alias.def_id) { + DefKind::AssocTy => { + if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id)) + { + ty::Inherent + } else { + ty::Projection + } + } + DefKind::OpaqueTy => ty::Opaque, + DefKind::TyAlias => ty::Weak, + kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), + } + } + + fn alias_term_kind(self, alias: ty::AliasTerm<'tcx>) -> ty::AliasTermKind { + match self.def_kind(alias.def_id) { + DefKind::AssocTy => { + if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id)) + { + ty::AliasTermKind::InherentTy + } else { + ty::AliasTermKind::ProjectionTy + } + } + DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy, + DefKind::TyAlias => ty::AliasTermKind::WeakTy, + DefKind::AssocConst => ty::AliasTermKind::ProjectionConst, + DefKind::AnonConst => ty::AliasTermKind::UnevaluatedConst, + kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), + } + } + + fn trait_ref_and_own_args_for_alias( + self, + def_id: Self::DefId, + args: Self::GenericArgs, + ) -> (rustc_type_ir::TraitRef, Self::GenericArgsSlice) { + 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); + let trait_generics = self.generics_of(trait_def_id); + ( + ty::TraitRef::new(self, trait_def_id, args.truncate_to(self, trait_generics)), + &args[trait_generics.count()..], + ) + } + fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs { self.mk_args(args) } + fn mk_args_from_iter(self, args: impl Iterator) -> Self::GenericArgs { + self.mk_args_from_iter(args) + } + fn check_and_mk_args( self, def_id: DefId, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index dc5e881843a..93ccc0a7de4 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -96,9 +96,9 @@ pub use self::list::{List, ListWithCachedTypeInfo}; pub use self::parameterized::ParameterizedOverTcx; pub use self::pattern::{Pattern, PatternKind}; pub use self::predicate::{ - Clause, ClauseKind, CoercePredicate, ExistentialPredicate, ExistentialPredicateStableCmpExt, - ExistentialProjection, ExistentialTraitRef, NormalizesTo, OutlivesPredicate, - PolyCoercePredicate, PolyExistentialPredicate, PolyExistentialProjection, + AliasTerm, Clause, ClauseKind, CoercePredicate, ExistentialPredicate, + ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef, NormalizesTo, + OutlivesPredicate, PolyCoercePredicate, PolyExistentialPredicate, PolyExistentialProjection, PolyExistentialTraitRef, PolyProjectionPredicate, PolyRegionOutlivesPredicate, PolySubtypePredicate, PolyTraitPredicate, PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, PredicateKind, ProjectionPredicate, RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, @@ -110,11 +110,11 @@ pub use self::region::{ }; pub use self::rvalue_scopes::RvalueScopes; pub use self::sty::{ - AliasTerm, AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, - CanonicalPolyFnSig, ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, - CoroutineClosureArgs, CoroutineClosureArgsParts, CoroutineClosureSignature, FnSig, GenSig, - InlineConstArgs, InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut, - UpvarArgs, VarianceDiagInfo, + AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig, + ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, CoroutineClosureArgs, + CoroutineClosureArgsParts, CoroutineClosureSignature, FnSig, GenSig, InlineConstArgs, + InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs, + VarianceDiagInfo, }; pub use self::trait_def::TraitDef; pub use self::typeck_results::{ diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index e78856517b2..16ca098853e 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -13,6 +13,7 @@ use crate::ty::{ }; pub type TraitRef<'tcx> = ir::TraitRef>; +pub type AliasTerm<'tcx> = ir::AliasTerm>; pub type ProjectionPredicate<'tcx> = ir::ProjectionPredicate>; pub type ExistentialPredicate<'tcx> = ir::ExistentialPredicate>; pub type ExistentialTraitRef<'tcx> = ir::ExistentialTraitRef>; diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 8d8ed70a757..3577db7234d 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3038,6 +3038,33 @@ define_print! { p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path())) } + ty::AliasTy<'tcx> { + let alias_term: ty::AliasTerm<'tcx> = (*self).into(); + p!(print(alias_term)) + } + + ty::AliasTerm<'tcx> { + match self.kind(cx.tcx()) { + ty::AliasTermKind::InherentTy => p!(pretty_print_inherent_projection(*self)), + ty::AliasTermKind::ProjectionTy + | ty::AliasTermKind::WeakTy + | ty::AliasTermKind::OpaqueTy + | ty::AliasTermKind::UnevaluatedConst + | ty::AliasTermKind::ProjectionConst => { + // If we're printing verbosely, or don't want to invoke queries + // (`is_impl_trait_in_trait`), then fall back to printing the def path. + // This is likely what you want if you're debugging the compiler anyways. + if !(cx.should_print_verbose() || with_reduced_queries()) + && cx.tcx().is_impl_trait_in_trait(self.def_id) + { + return cx.pretty_print_opaque_impl_type(self.def_id, self.args); + } else { + p!(print_def_path(self.def_id, self.args)); + } + } + } + } + ty::TraitPredicate<'tcx> { p!(print(self.trait_ref.self_ty()), ": "); p!(pretty_print_bound_constness(self.trait_ref)); @@ -3205,33 +3232,6 @@ define_print_and_forward_display! { } } - ty::AliasTy<'tcx> { - let alias_term: ty::AliasTerm<'tcx> = (*self).into(); - p!(print(alias_term)) - } - - ty::AliasTerm<'tcx> { - match self.kind(cx.tcx()) { - ty::AliasTermKind::InherentTy => p!(pretty_print_inherent_projection(*self)), - ty::AliasTermKind::ProjectionTy - | ty::AliasTermKind::WeakTy - | ty::AliasTermKind::OpaqueTy - | ty::AliasTermKind::UnevaluatedConst - | ty::AliasTermKind::ProjectionConst => { - // If we're printing verbosely, or don't want to invoke queries - // (`is_impl_trait_in_trait`), then fall back to printing the def path. - // This is likely what you want if you're debugging the compiler anyways. - if !(cx.should_print_verbose() || with_reduced_queries()) - && cx.tcx().is_impl_trait_in_trait(self.def_id) - { - return cx.pretty_print_opaque_impl_type(self.def_id, self.args); - } else { - p!(print_def_path(self.def_id, self.args)); - } - } - } - } - ty::Predicate<'tcx> { p!(print(self.kind())) } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 6abd685343b..7523cd15320 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -7,7 +7,7 @@ use crate::mir::interpret; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; +use crate::ty::{self, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; use rustc_ast_ir::try_visit; use rustc_ast_ir::visit::VisitorResult; use rustc_hir::def::Namespace; @@ -164,23 +164,6 @@ impl<'tcx> fmt::Debug for ty::Clause<'tcx> { } } -impl<'tcx> fmt::Debug for AliasTy<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - WithInfcx::with_no_infcx(self).fmt(f) - } -} -impl<'tcx> DebugWithInfcx> for AliasTy<'tcx> { - fn fmt>>( - this: WithInfcx<'_, Infcx, &Self>, - f: &mut core::fmt::Formatter<'_>, - ) -> core::fmt::Result { - f.debug_struct("AliasTy") - .field("args", &this.map(|data| data.args)) - .field("def_id", &this.data.def_id) - .finish() - } -} - impl<'tcx> DebugWithInfcx> for Pattern<'tcx> { fn fmt>>( this: WithInfcx<'_, Infcx, &Self>, @@ -230,23 +213,6 @@ impl<'tcx> DebugWithInfcx> for ty::consts::Expr<'tcx> { } } -impl<'tcx> fmt::Debug for ty::UnevaluatedConst<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - WithInfcx::with_no_infcx(self).fmt(f) - } -} -impl<'tcx> DebugWithInfcx> for ty::UnevaluatedConst<'tcx> { - fn fmt>>( - this: WithInfcx<'_, Infcx, &Self>, - f: &mut core::fmt::Formatter<'_>, - ) -> core::fmt::Result { - f.debug_struct("UnevaluatedConst") - .field("def", &this.data.def) - .field("args", &this.wrap(this.data.args)) - .finish() - } -} - impl<'tcx> fmt::Debug for ty::Const<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { WithInfcx::with_no_infcx(self).fmt(f) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 16301633247..e4396c6f20b 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -28,20 +28,17 @@ use std::iter; use std::ops::{ControlFlow, Deref, Range}; use ty::util::IntTypeExt; -use rustc_type_ir::BoundVar; -use rustc_type_ir::CollectAndApply; -use rustc_type_ir::DynKind; -use rustc_type_ir::TyKind as IrTyKind; use rustc_type_ir::TyKind::*; -use rustc_type_ir::TypeAndMut as IrTypeAndMut; +use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind}; use super::fold::FnMutDelegate; use super::GenericParamDefKind; // Re-export and re-parameterize some `I = TyCtxt<'tcx>` types here #[rustc_diagnostic_item = "TyKind"] -pub type TyKind<'tcx> = IrTyKind>; -pub type TypeAndMut<'tcx> = IrTypeAndMut>; +pub type TyKind<'tcx> = ir::TyKind>; +pub type TypeAndMut<'tcx> = ir::TypeAndMut>; +pub type AliasTy<'tcx> = ir::AliasTy>; pub trait Article { fn article(&self) -> &'static str; @@ -1105,371 +1102,6 @@ where } } -/// Represents the unprojected term of a projection goal. -/// -/// * For a projection, this would be `>::N<...>`. -/// * For an inherent projection, this would be `Ty::N<...>`. -/// * For an opaque type, there is no explicit syntax. -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct AliasTerm<'tcx> { - /// The parameters of the associated or opaque item. - /// - /// For a projection, these are the generic parameters for the trait and the - /// GAT parameters, if there are any. - /// - /// For an inherent projection, they consist of the self type and the GAT parameters, - /// if there are any. - /// - /// For RPIT the generic parameters are for the generics of the function, - /// while for TAIT it is used for the generic parameters of the alias. - pub args: GenericArgsRef<'tcx>, - - /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether - /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if - /// this is an opaque. - /// - /// During codegen, `tcx.type_of(def_id)` can be used to get the type of the - /// underlying type if the type is an opaque. - /// - /// Note that if this is an associated type, this is not the `DefId` of the - /// `TraitRef` containing this associated type, which is in `tcx.associated_item(def_id).container`, - /// aka. `tcx.parent(def_id)`. - pub def_id: DefId, - - /// This field exists to prevent the creation of `AliasTerm` without using - /// [AliasTerm::new]. - _use_alias_term_new_instead: (), -} - -// FIXME: Remove these when we uplift `AliasTerm` -use crate::ty::{DebugWithInfcx, InferCtxtLike, WithInfcx}; -impl<'tcx> std::fmt::Debug for AliasTerm<'tcx> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - WithInfcx::with_no_infcx(self).fmt(f) - } -} -impl<'tcx> DebugWithInfcx> for AliasTerm<'tcx> { - fn fmt>>( - this: WithInfcx<'_, Infcx, &Self>, - f: &mut std::fmt::Formatter<'_>, - ) -> std::fmt::Result { - f.debug_struct("AliasTerm") - .field("args", &this.map(|data| data.args)) - .field("def_id", &this.data.def_id) - .finish() - } -} - -impl<'tcx> rustc_type_ir::inherent::AliasTerm> for AliasTerm<'tcx> { - fn new( - interner: TyCtxt<'tcx>, - trait_def_id: DefId, - args: impl IntoIterator>>, - ) -> Self { - AliasTerm::new(interner, trait_def_id, args) - } - - fn def_id(self) -> DefId { - self.def_id - } - - fn args(self) -> ty::GenericArgsRef<'tcx> { - self.args - } - - fn trait_def_id(self, interner: TyCtxt<'tcx>) -> DefId { - self.trait_def_id(interner) - } - - fn self_ty(self) -> Ty<'tcx> { - self.self_ty() - } - - fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { - self.with_self_ty(tcx, self_ty) - } -} - -impl<'tcx> AliasTerm<'tcx> { - pub fn new( - tcx: TyCtxt<'tcx>, - def_id: DefId, - args: impl IntoIterator>>, - ) -> AliasTerm<'tcx> { - let args = tcx.check_and_mk_args(def_id, args); - AliasTerm { def_id, args, _use_alias_term_new_instead: () } - } - - pub fn expect_ty(self, tcx: TyCtxt<'tcx>) -> AliasTy<'tcx> { - match self.kind(tcx) { - ty::AliasTermKind::ProjectionTy - | ty::AliasTermKind::InherentTy - | ty::AliasTermKind::OpaqueTy - | ty::AliasTermKind::WeakTy => {} - ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => { - bug!("Cannot turn `UnevaluatedConst` into `AliasTy`") - } - } - ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () } - } - - pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasTermKind { - match tcx.def_kind(self.def_id) { - DefKind::AssocTy => { - if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) { - ty::AliasTermKind::InherentTy - } else { - ty::AliasTermKind::ProjectionTy - } - } - DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy, - DefKind::TyAlias => ty::AliasTermKind::WeakTy, - DefKind::AnonConst => ty::AliasTermKind::UnevaluatedConst, - DefKind::AssocConst => ty::AliasTermKind::ProjectionConst, - kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), - } - } -} - -/// The following methods work only with (trait) associated item projections. -impl<'tcx> AliasTerm<'tcx> { - pub fn self_ty(self) -> Ty<'tcx> { - self.args.type_at(0) - } - - pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { - AliasTerm::new( - tcx, - self.def_id, - [self_ty.into()].into_iter().chain(self.args.iter().skip(1)), - ) - } - - pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId { - match tcx.def_kind(self.def_id) { - DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id), - kind => bug!("expected a projection AliasTy; found {kind:?}"), - } - } - - /// Extracts the underlying trait reference from this projection. - /// For example, if this is a projection of `::Item`, - /// then this function would return a `T: Iterator` trait reference. - /// - /// NOTE: This will drop the args for generic associated types - /// consider calling [Self::trait_ref_and_own_args] to get those - /// as well. - pub fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> { - let def_id = self.trait_def_id(tcx); - ty::TraitRef::new(tcx, def_id, self.args.truncate_to(tcx, tcx.generics_of(def_id))) - } - - /// Extracts the underlying trait reference and own args from this projection. - /// 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, - tcx: TyCtxt<'tcx>, - ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) { - let trait_def_id = self.trait_def_id(tcx); - let trait_generics = tcx.generics_of(trait_def_id); - ( - ty::TraitRef::new(tcx, trait_def_id, self.args.truncate_to(tcx, trait_generics)), - &self.args[trait_generics.count()..], - ) - } - - pub fn to_term(self, tcx: TyCtxt<'tcx>) -> ty::Term<'tcx> { - match self.kind(tcx) { - ty::AliasTermKind::ProjectionTy => Ty::new_alias( - tcx, - ty::Projection, - AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, - ) - .into(), - ty::AliasTermKind::InherentTy => Ty::new_alias( - tcx, - ty::Inherent, - AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, - ) - .into(), - ty::AliasTermKind::OpaqueTy => Ty::new_alias( - tcx, - ty::Opaque, - AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, - ) - .into(), - ty::AliasTermKind::WeakTy => Ty::new_alias( - tcx, - ty::Weak, - AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, - ) - .into(), - ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => { - ty::Const::new_unevaluated( - tcx, - ty::UnevaluatedConst::new(self.def_id, self.args), - tcx.type_of(self.def_id).instantiate(tcx, self.args), - ) - .into() - } - } - } -} - -impl<'tcx> From> for AliasTerm<'tcx> { - fn from(ty: AliasTy<'tcx>) -> Self { - AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () } - } -} - -impl<'tcx> From> for AliasTerm<'tcx> { - fn from(ct: ty::UnevaluatedConst<'tcx>) -> Self { - AliasTerm { args: ct.args, def_id: ct.def, _use_alias_term_new_instead: () } - } -} - -/// Represents the projection of an associated, opaque, or lazy-type-alias type. -/// -/// * For a projection, this would be `>::N<...>`. -/// * For an inherent projection, this would be `Ty::N<...>`. -/// * For an opaque type, there is no explicit syntax. -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct AliasTy<'tcx> { - /// The parameters of the associated or opaque type. - /// - /// For a projection, these are the generic parameters for the trait and the - /// GAT parameters, if there are any. - /// - /// For an inherent projection, they consist of the self type and the GAT parameters, - /// if there are any. - /// - /// For RPIT the generic parameters are for the generics of the function, - /// while for TAIT it is used for the generic parameters of the alias. - pub args: GenericArgsRef<'tcx>, - - /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether - /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if - /// this is an opaque. - /// - /// During codegen, `tcx.type_of(def_id)` can be used to get the type of the - /// underlying type if the type is an opaque. - /// - /// Note that if this is an associated type, this is not the `DefId` of the - /// `TraitRef` containing this associated type, which is in `tcx.associated_item(def_id).container`, - /// aka. `tcx.parent(def_id)`. - pub def_id: DefId, - - /// This field exists to prevent the creation of `AliasT` without using - /// [AliasTy::new]. - _use_alias_ty_new_instead: (), -} - -impl<'tcx> AliasTy<'tcx> { - pub fn new( - tcx: TyCtxt<'tcx>, - def_id: DefId, - args: impl IntoIterator>>, - ) -> ty::AliasTy<'tcx> { - let args = tcx.check_and_mk_args(def_id, args); - ty::AliasTy { def_id, args, _use_alias_ty_new_instead: () } - } - - pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasTyKind { - match tcx.def_kind(self.def_id) { - DefKind::AssocTy - if let DefKind::Impl { of_trait: false } = - tcx.def_kind(tcx.parent(self.def_id)) => - { - ty::Inherent - } - DefKind::AssocTy => ty::Projection, - DefKind::OpaqueTy => ty::Opaque, - DefKind::TyAlias => ty::Weak, - kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), - } - } - - /// Whether this alias type is an opaque. - pub fn is_opaque(self, tcx: TyCtxt<'tcx>) -> bool { - matches!(self.kind(tcx), ty::Opaque) - } - - pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - Ty::new_alias(tcx, self.kind(tcx), self) - } -} - -/// The following methods work only with (trait) associated type projections. -impl<'tcx> AliasTy<'tcx> { - pub fn self_ty(self) -> Ty<'tcx> { - self.args.type_at(0) - } - - pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { - AliasTy::new(tcx, self.def_id, [self_ty.into()].into_iter().chain(self.args.iter().skip(1))) - } - - pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId { - match tcx.def_kind(self.def_id) { - DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id), - kind => bug!("expected a projection AliasTy; found {kind:?}"), - } - } - - /// Extracts the underlying trait reference and own args from this projection. - /// 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, - tcx: TyCtxt<'tcx>, - ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) { - let trait_def_id = self.trait_def_id(tcx); - let trait_generics = tcx.generics_of(trait_def_id); - ( - ty::TraitRef::new(tcx, trait_def_id, self.args.truncate_to(tcx, trait_generics)), - &self.args[trait_generics.count()..], - ) - } - - /// Extracts the underlying trait reference from this projection. - /// For example, if this is a projection of `::Item`, - /// then this function would return a `T: Iterator` trait reference. - /// - /// WARNING: This will drop the args for generic associated types - /// consider calling [Self::trait_ref_and_own_args] to get those - /// as well. - pub fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> { - let def_id = self.trait_def_id(tcx); - ty::TraitRef::new(tcx, def_id, self.args.truncate_to(tcx, tcx.generics_of(def_id))) - } -} - -/// The following methods work only with inherent associated type projections. -impl<'tcx> AliasTy<'tcx> { - /// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that. - /// - /// Does the following transformation: - /// - /// ```text - /// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m] - /// - /// I_i impl args - /// P_j GAT args - /// ``` - pub fn rebase_inherent_args_onto_impl( - self, - impl_args: ty::GenericArgsRef<'tcx>, - tcx: TyCtxt<'tcx>, - ) -> ty::GenericArgsRef<'tcx> { - debug_assert_eq!(self.kind(tcx), ty::Inherent); - - tcx.mk_args_from_iter(impl_args.into_iter().chain(self.args.into_iter().skip(1))) - } -} - #[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] pub struct GenSig<'tcx> { pub resume_ty: Ty<'tcx>, @@ -2020,6 +1652,18 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> { fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self { Ty::new_bound(tcx, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon }) } + + fn new_alias( + interner: TyCtxt<'tcx>, + kind: ty::AliasTyKind, + alias_ty: ty::AliasTy<'tcx>, + ) -> Self { + Ty::new_alias(interner, kind, alias_ty) + } + + fn into_term(self) -> ty::Term<'tcx> { + self.into() + } } /// Type utilities diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index c748cdf6ed2..af07e9ff96b 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -2,6 +2,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; #[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use std::fmt; use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx}; @@ -86,6 +87,46 @@ impl DebugWithInfcx for ConstKind { } } +/// An unevaluated (potentially generic) constant used in the type-system. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct UnevaluatedConst { + pub def: I::DefId, + pub args: I::GenericArgs, +} + +impl UnevaluatedConst { + #[inline] + pub fn new(def: I::DefId, args: I::GenericArgs) -> UnevaluatedConst { + UnevaluatedConst { def, args } + } +} + +impl fmt::Debug for UnevaluatedConst { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + WithInfcx::with_no_infcx(self).fmt(f) + } +} +impl DebugWithInfcx for UnevaluatedConst { + fn fmt>( + this: WithInfcx<'_, Infcx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + f.debug_struct("UnevaluatedConst") + .field("def", &this.data.def) + .field("args", &this.wrap(this.data.args)) + .finish() + } +} + rustc_index::newtype_index! { /// A **`const`** **v**ariable **ID**. #[encodable] diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 5e981636438..0a964801ce7 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -5,7 +5,8 @@ use std::ops::Deref; use crate::fold::TypeSuperFoldable; use crate::visit::{Flags, TypeSuperVisitable}; use crate::{ - BoundVar, ConstKind, DebruijnIndex, DebugWithInfcx, Interner, RegionKind, TyKind, UniverseIndex, + AliasTy, AliasTyKind, BoundVar, ConstKind, DebruijnIndex, DebugWithInfcx, Interner, RegionKind, + TyKind, UnevaluatedConst, UniverseIndex, }; pub trait Ty>: @@ -20,6 +21,10 @@ pub trait Ty>: + Flags { fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self; + + fn new_alias(interner: I, kind: AliasTyKind, alias_ty: AliasTy) -> Self; + + fn into_term(self) -> I::Term; } pub trait Region>: @@ -43,7 +48,11 @@ pub trait Const>: { fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar, ty: I::Ty) -> Self; + fn new_unevaluated(interner: I, uv: UnevaluatedConst, ty: I::Ty) -> Self; + fn ty(self) -> I::Ty; + + fn into_term(self) -> I::Term; } pub trait GenericsOf> { @@ -89,21 +98,3 @@ pub trait BoundVars { fn has_no_bound_vars(&self) -> bool; } - -pub trait AliasTerm: Copy + DebugWithInfcx + Hash + Eq + Sized { - fn new( - interner: I, - trait_def_id: I::DefId, - args: impl IntoIterator>, - ) -> Self; - - fn def_id(self) -> I::DefId; - - fn args(self) -> I::GenericArgs; - - fn trait_def_id(self, interner: I) -> I::DefId; - - fn self_ty(self) -> I::Ty; - - fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self; -} diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index af0e833b9e9..d6680977168 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -6,13 +6,16 @@ use crate::inherent::*; use crate::ir_print::IrPrint; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{ - CanonicalVarInfo, CoercePredicate, DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, - NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, + AliasTerm, AliasTermKind, AliasTy, AliasTyKind, CanonicalVarInfo, CoercePredicate, + DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, NormalizesTo, ProjectionPredicate, + SubtypePredicate, TraitPredicate, TraitRef, }; pub trait Interner: Sized + Copy + + IrPrint> + + IrPrint> + IrPrint> + IrPrint> + IrPrint> @@ -27,6 +30,7 @@ pub trait Interner: type AdtDef: Copy + Debug + Hash + Eq; type GenericArgs: GenericArgs; + type GenericArgsSlice: Copy + Debug + Hash + Eq; type GenericArg: Copy + DebugWithInfcx + Hash + Eq; type Term: Copy + Debug + Hash + Eq; @@ -39,7 +43,6 @@ pub trait Interner: // Kinds of tys type Ty: Ty; type Tys: Copy + Debug + Hash + Eq + IntoIterator; - type AliasTy: Copy + DebugWithInfcx + Hash + Eq + Sized; type ParamTy: Copy + Debug + Hash + Eq; type BoundTy: Copy + Debug + Hash + Eq; type PlaceholderTy: PlaceholderLike; @@ -74,7 +77,6 @@ pub trait Interner: type RegionOutlivesPredicate: Copy + Debug + Hash + Eq; type TypeOutlivesPredicate: Copy + Debug + Hash + Eq; type ProjectionPredicate: Copy + Debug + Hash + Eq; - type AliasTerm: AliasTerm; type NormalizesTo: Copy + Debug + Hash + Eq; type SubtypePredicate: Copy + Debug + Hash + Eq; type CoercePredicate: Copy + Debug + Hash + Eq; @@ -86,8 +88,23 @@ pub trait Interner: type GenericsOf: GenericsOf; fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf; + // FIXME: Remove after uplifting `EarlyBinder` + fn type_of_instantiated(self, def_id: Self::DefId, args: Self::GenericArgs) -> Self::Ty; + + fn alias_ty_kind(self, alias: AliasTy) -> AliasTyKind; + + fn alias_term_kind(self, alias: AliasTerm) -> AliasTermKind; + + fn trait_ref_and_own_args_for_alias( + self, + def_id: Self::DefId, + args: Self::GenericArgs, + ) -> (TraitRef, Self::GenericArgsSlice); + fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs; + fn mk_args_from_iter(self, args: impl Iterator) -> Self::GenericArgs; + fn check_and_mk_args( self, def_id: Self::DefId, diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs index 5885139754a..2a766d0bc09 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::{ - CoercePredicate, ExistentialProjection, ExistentialTraitRef, Interner, NormalizesTo, - ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, + AliasTerm, AliasTy, CoercePredicate, ExistentialProjection, ExistentialTraitRef, Interner, + NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, }; pub trait IrPrint { @@ -43,6 +43,8 @@ define_display_via_print!( NormalizesTo, SubtypePredicate, CoercePredicate, + AliasTy, + AliasTerm, ); 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 71f198d2b8e..1ec237d7cd5 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -6,7 +6,9 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen use crate::inherent::*; use crate::visit::TypeVisitableExt as _; -use crate::{DebugWithInfcx, Interner}; +use crate::{ + AliasTy, AliasTyKind, DebugWithInfcx, InferCtxtLike, Interner, UnevaluatedConst, WithInfcx, +}; /// A complete reference to a trait. These take numerous guises in syntax, /// but perhaps the most recognizable form is in a where-clause: @@ -272,20 +274,20 @@ impl ExistentialProjection { /// For example, if this is a projection of `exists T. ::Item == X`, /// then this function would return an `exists T. T: Iterator` existential trait /// reference. - pub fn trait_ref(&self, tcx: I) -> ExistentialTraitRef { - let def_id = tcx.parent(self.def_id); - let args_count = tcx.generics_of(def_id).count() - 1; - let args = tcx.mk_args(&self.args[..args_count]); + pub fn trait_ref(&self, interner: I) -> ExistentialTraitRef { + let def_id = interner.parent(self.def_id); + let args_count = interner.generics_of(def_id).count() - 1; + let args = interner.mk_args(&self.args[..args_count]); ExistentialTraitRef { def_id, args } } - pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> ProjectionPredicate { + pub fn with_self_ty(&self, interner: I, self_ty: I::Ty) -> ProjectionPredicate { // otherwise the escaping regions would be captured by the binders debug_assert!(!self_ty.has_escaping_bound_vars()); ProjectionPredicate { - projection_term: I::AliasTerm::new( - tcx, + projection_term: AliasTerm::new( + interner, self.def_id, [self_ty.into()].into_iter().chain(self.args), ), @@ -293,13 +295,13 @@ impl ExistentialProjection { } } - pub fn erase_self_ty(tcx: I, projection_predicate: ProjectionPredicate) -> Self { + pub fn erase_self_ty(interner: I, projection_predicate: ProjectionPredicate) -> Self { // Assert there is a Self. - projection_predicate.projection_term.args().type_at(0); + projection_predicate.projection_term.args.type_at(0); Self { - def_id: projection_predicate.projection_term.def_id(), - args: tcx.mk_args(&projection_predicate.projection_term.args()[1..]), + def_id: projection_predicate.projection_term.def_id, + args: interner.mk_args(&projection_predicate.projection_term.args[1..]), term: projection_predicate.term, } } @@ -339,6 +341,190 @@ impl AliasTermKind { } } +/// Represents the unprojected term of a projection goal. +/// +/// * For a projection, this would be `>::N<...>`. +/// * For an inherent projection, this would be `Ty::N<...>`. +/// * For an opaque type, there is no explicit syntax. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct AliasTerm { + /// The parameters of the associated or opaque item. + /// + /// For a projection, these are the generic parameters for the trait and the + /// GAT parameters, if there are any. + /// + /// For an inherent projection, they consist of the self type and the GAT parameters, + /// if there are any. + /// + /// For RPIT the generic parameters are for the generics of the function, + /// while for TAIT it is used for the generic parameters of the alias. + pub args: I::GenericArgs, + + /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether + /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if + /// this is an opaque. + /// + /// During codegen, `interner.type_of(def_id)` can be used to get the type of the + /// underlying type if the type is an opaque. + /// + /// Note that if this is an associated type, this is not the `DefId` of the + /// `TraitRef` containing this associated type, which is in `interner.associated_item(def_id).container`, + /// aka. `interner.parent(def_id)`. + pub def_id: I::DefId, + + /// This field exists to prevent the creation of `AliasTerm` without using + /// [AliasTerm::new]. + _use_alias_term_new_instead: (), +} + +impl std::fmt::Debug for AliasTerm { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + WithInfcx::with_no_infcx(self).fmt(f) + } +} +impl DebugWithInfcx for AliasTerm { + fn fmt>( + this: WithInfcx<'_, Infcx, &Self>, + f: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + f.debug_struct("AliasTerm") + .field("args", &this.map(|data| data.args)) + .field("def_id", &this.data.def_id) + .finish() + } +} + +impl AliasTerm { + pub fn new( + interner: I, + def_id: I::DefId, + args: impl IntoIterator>, + ) -> AliasTerm { + let args = interner.check_and_mk_args(def_id, args); + AliasTerm { def_id, args, _use_alias_term_new_instead: () } + } + + pub fn expect_ty(self, interner: I) -> AliasTy { + match self.kind(interner) { + AliasTermKind::ProjectionTy + | AliasTermKind::InherentTy + | AliasTermKind::OpaqueTy + | AliasTermKind::WeakTy => {} + AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => { + panic!("Cannot turn `UnevaluatedConst` into `AliasTy`") + } + } + AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () } + } + + pub fn kind(self, interner: I) -> AliasTermKind { + interner.alias_term_kind(self) + } + + pub fn to_term(self, interner: I) -> I::Term { + match self.kind(interner) { + AliasTermKind::ProjectionTy => Ty::new_alias( + interner, + AliasTyKind::Projection, + AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, + ) + .into_term(), + AliasTermKind::InherentTy => Ty::new_alias( + interner, + AliasTyKind::Inherent, + AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, + ) + .into_term(), + AliasTermKind::OpaqueTy => Ty::new_alias( + interner, + AliasTyKind::Opaque, + AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, + ) + .into_term(), + AliasTermKind::WeakTy => Ty::new_alias( + interner, + AliasTyKind::Weak, + AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, + ) + .into_term(), + AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => { + I::Const::new_unevaluated( + interner, + UnevaluatedConst::new(self.def_id, self.args), + interner.type_of_instantiated(self.def_id, self.args), + ) + .into_term() + } + } + } +} + +/// The following methods work only with (trait) associated type projections. +impl AliasTerm { + pub fn self_ty(self) -> I::Ty { + self.args.type_at(0) + } + + pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + AliasTerm::new( + interner, + self.def_id, + [self_ty.into()].into_iter().chain(self.args.into_iter().skip(1)), + ) + } + + pub fn trait_def_id(self, interner: I) -> I::DefId { + assert!( + matches!( + self.kind(interner), + AliasTermKind::ProjectionTy | AliasTermKind::ProjectionConst + ), + "expected a projection" + ); + interner.parent(self.def_id) + } + + /// Extracts the underlying trait reference and own args from this projection. + /// 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) { + interner.trait_ref_and_own_args_for_alias(self.def_id, self.args) + } + + /// Extracts the underlying trait reference from this projection. + /// For example, if this is a projection of `::Item`, + /// then this function would return a `T: Iterator` trait reference. + /// + /// WARNING: This will drop the args for generic associated types + /// consider calling [Self::trait_ref_and_own_args] to get those + /// as well. + pub fn trait_ref(self, interner: I) -> TraitRef { + self.trait_ref_and_own_args(interner).0 + } +} + +impl From> for AliasTerm { + fn from(ty: AliasTy) -> Self { + AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () } + } +} + +impl From> for AliasTerm { + fn from(ct: UnevaluatedConst) -> Self { + AliasTerm { args: ct.args, def_id: ct.def, _use_alias_term_new_instead: () } + } +} + /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: /// @@ -362,7 +548,7 @@ impl AliasTermKind { #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct ProjectionPredicate { - pub projection_term: I::AliasTerm, + pub projection_term: AliasTerm, pub term: I::Term, } @@ -371,16 +557,16 @@ impl ProjectionPredicate { self.projection_term.self_ty() } - pub fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> ProjectionPredicate { - Self { projection_term: self.projection_term.with_self_ty(tcx, self_ty), ..self } + pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> ProjectionPredicate { + Self { projection_term: self.projection_term.with_self_ty(interner, self_ty), ..self } } - pub fn trait_def_id(self, tcx: I) -> I::DefId { - self.projection_term.trait_def_id(tcx) + pub fn trait_def_id(self, interner: I) -> I::DefId { + self.projection_term.trait_def_id(interner) } pub fn def_id(self) -> I::DefId { - self.projection_term.def_id() + self.projection_term.def_id } } @@ -403,7 +589,7 @@ impl fmt::Debug for ProjectionPredicate { #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct NormalizesTo { - pub alias: I::AliasTerm, + pub alias: AliasTerm, pub term: I::Term, } @@ -412,16 +598,16 @@ impl NormalizesTo { self.alias.self_ty() } - pub fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> NormalizesTo { - Self { alias: self.alias.with_self_ty(tcx, self_ty), ..self } + pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> NormalizesTo { + Self { alias: self.alias.with_self_ty(interner, self_ty), ..self } } - pub fn trait_def_id(self, tcx: I) -> I::DefId { - self.alias.trait_def_id(tcx) + pub fn trait_def_id(self, interner: I) -> I::DefId { + self.alias.trait_def_id(interner) } pub fn def_id(self) -> I::DefId { - self.alias.def_id() + self.alias.def_id } } diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 6e544d0e6ac..672c890f94e 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -4,11 +4,11 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::unify::{EqUnifyValue, UnifyKey}; #[cfg(feature = "nightly")] use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable}; -use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; +use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use std::fmt; -use crate::Interner; -use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, WithInfcx}; +use crate::inherent::*; +use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, TraitRef, WithInfcx}; use self::TyKind::*; @@ -88,7 +88,7 @@ pub enum TyKind { /// for `struct List` and the args `[i32]`. /// /// Note that generic parameters in fields only get lazily instantiated - /// by using something like `adt_def.all_fields().map(|field| field.ty(tcx, args))`. + /// by using something like `adt_def.all_fields().map(|field| field.ty(interner, args))`. Adt(I::AdtDef, I::GenericArgs), /// An unsized FFI type that is opaque to Rust. Written as `extern type T`. @@ -201,7 +201,7 @@ pub enum TyKind { /// A projection, opaque type, weak type alias, or inherent associated type. /// All of these types are represented as pairs of def-id and args, and can /// be normalized, so they are grouped conceptually. - Alias(AliasTyKind, I::AliasTy), + Alias(AliasTyKind, AliasTy), /// A type parameter; for example, `T` in `fn f(x: T) {}`. Param(I::ParamTy), @@ -422,6 +422,154 @@ impl fmt::Debug for TyKind { } } +/// Represents the projection of an associated, opaque, or lazy-type-alias type. +/// +/// * For a projection, this would be `>::N<...>`. +/// * For an inherent projection, this would be `Ty::N<...>`. +/// * For an opaque type, there is no explicit syntax. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct AliasTy { + /// The parameters of the associated or opaque type. + /// + /// For a projection, these are the generic parameters for the trait and the + /// GAT parameters, if there are any. + /// + /// For an inherent projection, they consist of the self type and the GAT parameters, + /// if there are any. + /// + /// For RPIT the generic parameters are for the generics of the function, + /// while for TAIT it is used for the generic parameters of the alias. + pub args: I::GenericArgs, + + /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether + /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if + /// this is an opaque. + /// + /// During codegen, `interner.type_of(def_id)` can be used to get the type of the + /// underlying type if the type is an opaque. + /// + /// Note that if this is an associated type, this is not the `DefId` of the + /// `TraitRef` containing this associated type, which is in `interner.associated_item(def_id).container`, + /// aka. `interner.parent(def_id)`. + pub def_id: I::DefId, + + /// This field exists to prevent the creation of `AliasTy` without using + /// [AliasTy::new]. + pub(crate) _use_alias_ty_new_instead: (), +} + +impl AliasTy { + pub fn new( + interner: I, + def_id: I::DefId, + args: impl IntoIterator>, + ) -> AliasTy { + let args = interner.check_and_mk_args(def_id, args); + AliasTy { def_id, args, _use_alias_ty_new_instead: () } + } + + pub fn kind(self, interner: I) -> AliasTyKind { + interner.alias_ty_kind(self) + } + + /// Whether this alias type is an opaque. + pub fn is_opaque(self, interner: I) -> bool { + matches!(self.kind(interner), AliasTyKind::Opaque) + } + + pub fn to_ty(self, interner: I) -> I::Ty { + Ty::new_alias(interner, self.kind(interner), self) + } +} + +/// The following methods work only with (trait) associated type projections. +impl AliasTy { + pub fn self_ty(self) -> I::Ty { + self.args.type_at(0) + } + + pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + AliasTy::new( + interner, + self.def_id, + [self_ty.into()].into_iter().chain(self.args.into_iter().skip(1)), + ) + } + + pub fn trait_def_id(self, interner: I) -> I::DefId { + assert_eq!(self.kind(interner), AliasTyKind::Projection, "expected a projection"); + interner.parent(self.def_id) + } + + /// Extracts the underlying trait reference and own args from this projection. + /// 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) { + debug_assert_eq!(self.kind(interner), AliasTyKind::Projection); + interner.trait_ref_and_own_args_for_alias(self.def_id, self.args) + } + + /// Extracts the underlying trait reference from this projection. + /// For example, if this is a projection of `::Item`, + /// then this function would return a `T: Iterator` trait reference. + /// + /// WARNING: This will drop the args for generic associated types + /// consider calling [Self::trait_ref_and_own_args] to get those + /// as well. + pub fn trait_ref(self, interner: I) -> TraitRef { + self.trait_ref_and_own_args(interner).0 + } +} + +/// The following methods work only with inherent associated type projections. +impl AliasTy { + /// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that. + /// + /// Does the following transformation: + /// + /// ```text + /// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m] + /// + /// I_i impl args + /// P_j GAT args + /// ``` + pub fn rebase_inherent_args_onto_impl( + self, + impl_args: I::GenericArgs, + interner: I, + ) -> I::GenericArgs { + debug_assert_eq!(self.kind(interner), AliasTyKind::Inherent); + interner.mk_args_from_iter(impl_args.into_iter().chain(self.args.into_iter().skip(1))) + } +} + +impl fmt::Debug for AliasTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + WithInfcx::with_no_infcx(self).fmt(f) + } +} +impl DebugWithInfcx for AliasTy { + fn fmt>( + this: WithInfcx<'_, Infcx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + f.debug_struct("AliasTy") + .field("args", &this.map(|data| data.args)) + .field("def_id", &this.data.def_id) + .finish() + } +} + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] pub enum IntTy { From 9f8cdb286ec2660c7abe65f687bb29cb0b207fa5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 13 May 2024 15:22:47 -0400 Subject: [PATCH 06/14] Remove to_term --- compiler/rustc_middle/src/ty/consts.rs | 4 ---- compiler/rustc_middle/src/ty/sty.rs | 4 ---- compiler/rustc_type_ir/src/inherent.rs | 6 ++---- compiler/rustc_type_ir/src/predicate.rs | 10 +++++----- 4 files changed, 7 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 27a4abaa0b6..9dc30447f0e 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -195,10 +195,6 @@ impl<'tcx> rustc_type_ir::inherent::Const> for Const<'tcx> { fn ty(self) -> Ty<'tcx> { self.ty() } - - fn into_term(self) -> ty::Term<'tcx> { - self.into() - } } impl<'tcx> Const<'tcx> { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e4396c6f20b..74b03d6db66 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1660,10 +1660,6 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> { ) -> Self { Ty::new_alias(interner, kind, alias_ty) } - - fn into_term(self) -> ty::Term<'tcx> { - self.into() - } } /// Type utilities diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 0a964801ce7..92b1e08ab0a 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -15,6 +15,7 @@ pub trait Ty>: + Hash + Eq + Into + + Into + IntoKind> + TypeSuperVisitable + TypeSuperFoldable @@ -23,8 +24,6 @@ pub trait Ty>: fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self; fn new_alias(interner: I, kind: AliasTyKind, alias_ty: AliasTy) -> Self; - - fn into_term(self) -> I::Term; } pub trait Region>: @@ -41,6 +40,7 @@ pub trait Const>: + Hash + Eq + Into + + Into + IntoKind> + TypeSuperVisitable + TypeSuperFoldable @@ -51,8 +51,6 @@ pub trait Const>: fn new_unevaluated(interner: I, uv: UnevaluatedConst, ty: I::Ty) -> Self; fn ty(self) -> I::Ty; - - fn into_term(self) -> I::Term; } pub trait GenericsOf> { diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 1ec237d7cd5..b6c7c2c348c 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -437,32 +437,32 @@ impl AliasTerm { AliasTyKind::Projection, AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, ) - .into_term(), + .into(), AliasTermKind::InherentTy => Ty::new_alias( interner, AliasTyKind::Inherent, AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, ) - .into_term(), + .into(), AliasTermKind::OpaqueTy => Ty::new_alias( interner, AliasTyKind::Opaque, AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, ) - .into_term(), + .into(), AliasTermKind::WeakTy => Ty::new_alias( interner, AliasTyKind::Weak, AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, ) - .into_term(), + .into(), AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => { I::Const::new_unevaluated( interner, UnevaluatedConst::new(self.def_id, self.args), interner.type_of_instantiated(self.def_id, self.args), ) - .into_term() + .into() } } } From 45b50d303c52a11785469364c82e083cbe14140b Mon Sep 17 00:00:00 2001 From: Oneirical Date: Mon, 13 May 2024 22:56:21 -0400 Subject: [PATCH 07/14] lto function, static_library call, rename --- src/tools/run-make-support/src/rustc.rs | 7 +++---- .../bar.rs | 0 .../foo.c | 0 .../foo.rs | 0 .../rmake.rs | 8 ++++---- 5 files changed, 7 insertions(+), 8 deletions(-) rename tests/run-make/{issue-14500 => reachable-extern-fn-available-lto}/bar.rs (100%) rename tests/run-make/{issue-14500 => reachable-extern-fn-available-lto}/foo.c (100%) rename tests/run-make/{issue-14500 => reachable-extern-fn-available-lto}/foo.rs (100%) rename tests/run-make/{issue-14500 => reachable-extern-fn-available-lto}/rmake.rs (78%) diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index c92e9f9b11f..0de5a38c0c4 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -150,10 +150,9 @@ impl Rustc { self } - /// Pass a codegen option. - pub fn codegen_option(&mut self, option: &str) -> &mut Self { - self.cmd.arg("-C"); - self.cmd.arg(option); + /// Enables link time optimizations in rustc. Equivalent to `-Clto``. + pub fn lto(&mut self) -> &mut Self { + self.cmd.arg("-Clto"); self } diff --git a/tests/run-make/issue-14500/bar.rs b/tests/run-make/reachable-extern-fn-available-lto/bar.rs similarity index 100% rename from tests/run-make/issue-14500/bar.rs rename to tests/run-make/reachable-extern-fn-available-lto/bar.rs diff --git a/tests/run-make/issue-14500/foo.c b/tests/run-make/reachable-extern-fn-available-lto/foo.c similarity index 100% rename from tests/run-make/issue-14500/foo.c rename to tests/run-make/reachable-extern-fn-available-lto/foo.c diff --git a/tests/run-make/issue-14500/foo.rs b/tests/run-make/reachable-extern-fn-available-lto/foo.rs similarity index 100% rename from tests/run-make/issue-14500/foo.rs rename to tests/run-make/reachable-extern-fn-available-lto/foo.rs diff --git a/tests/run-make/issue-14500/rmake.rs b/tests/run-make/reachable-extern-fn-available-lto/rmake.rs similarity index 78% rename from tests/run-make/issue-14500/rmake.rs rename to tests/run-make/reachable-extern-fn-available-lto/rmake.rs index 58f632e5909..3e38b92b2b8 100644 --- a/tests/run-make/issue-14500/rmake.rs +++ b/tests/run-make/reachable-extern-fn-available-lto/rmake.rs @@ -1,5 +1,5 @@ // Test to make sure that reachable extern fns are always available in final -// productcs, including when LTO is used. +// productcs, including when link time optimizations (LTO) are used. // In this test, the `foo` crate has a reahable symbol, // and is a dependency of the `bar` crate. When the `bar` crate @@ -9,15 +9,15 @@ //@ ignore-cross-compile -use run_make_support::{cc, extra_c_flags, run, rustc, tmp_dir}; +use run_make_support::{cc, extra_c_flags, run, rustc, static_lib, tmp_dir}; fn main() { - let libbar_path = tmp_dir().join("libbar.a"); + let libbar_path = static_lib("bar"); rustc().input("foo.rs").crate_type("rlib").run(); rustc() .input("bar.rs") .crate_type("staticlib") - .codegen_option("lto") + .lto() .library_search_path(".") .output(&libbar_path) .run(); From 8f97a2588caa808b4d46dc3224de5d40bbbcd94b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 13 May 2024 22:36:48 -0400 Subject: [PATCH 08/14] Add test to make sure suggestions are still quick --- ...obe-for-diagnostic-doesnt-do-extra-work.rs | 163 ++++++++++++++++++ ...for-diagnostic-doesnt-do-extra-work.stderr | 84 +++++++++ 2 files changed, 247 insertions(+) create mode 100644 tests/ui/methods/probe-for-diagnostic-doesnt-do-extra-work.rs create mode 100644 tests/ui/methods/probe-for-diagnostic-doesnt-do-extra-work.stderr diff --git a/tests/ui/methods/probe-for-diagnostic-doesnt-do-extra-work.rs b/tests/ui/methods/probe-for-diagnostic-doesnt-do-extra-work.rs new file mode 100644 index 00000000000..b6bc450dcc7 --- /dev/null +++ b/tests/ui/methods/probe-for-diagnostic-doesnt-do-extra-work.rs @@ -0,0 +1,163 @@ +#![allow(non_snake_case)] + +// Ensures that we don't spend an unnecessary amount of compiler time building +// suggestions for mistyped methods. This used to happen because when we had method +// lookup failures, we would do subsequent method lookups, and those would themselves +// do extra work that was unnecessary for the purposes of suggestions. +// Fixed by #125100. + +macro_rules! traits { + ($($name:ident),*) => { + $( + trait $name { + fn $name(&self); + } + )* + } +} + +traits!( + A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, + A21, A22, A23, A24, A25, A26, A27, A28, A29, A30, A31, A32, A33, A34, A35, A36, A37, A38, A39, + A40, A41, A42, A43, A44, A45, A46, A47, A48, A49, A50, A51, A52, A53, A54, A55, A56, A57, A58, + A59, A60, A61, A62, A63, A64, A65, A66, A67, A68, A69, A70, A71, A72, A73, A74, A75, A76, A77, + A78, A79, A80, A81, A82, A83, A84, A85, A86, A87, A88, A89, A90, A91, A92, A93, A94, A95, A96, + A97, A98, A99, A100, A101, A102, A103, A104, A105, A106, A107, A108, A109, A110, A111, A112, + A113, A114, A115, A116, A117, A118, A119, A120, A121, A122, A123, A124, A125, A126, A127, A128, + A129, A130, A131, A132, A133, A134, A135, A136, A137, A138, A139, A140, A141, A142, A143, A144, + A145, A146, A147, A148, A149, A150, A151, A152, A153, A154, A155, A156, A157, A158, A159, A160, + A161, A162, A163, A164, A165, A166, A167, A168, A169, A170, A171, A172, A173, A174, A175, A176, + A177, A178, A179, A180, A181, A182, A183, A184, A185, A186, A187, A188, A189, A190, A191, A192, + A193, A194, A195, A196, A197, A198, A199, A200, A201, A202, A203, A204, A205, A206, A207, A208, + A209, A210, A211, A212, A213, A214, A215, A216, A217, A218, A219, A220, A221, A222, A223, A224, + A225, A226, A227, A228, A229, A230, A231, A232, A233, A234, A235, A236, A237, A238, A239, A240, + A241, A242, A243, A244, A245, A246, A247, A248, A249, A250, A251, A252, A253, A254, A255, A256, + A257, A258, A259, A260, A261, A262, A263, A264, A265, A266, A267, A268, A269, A270, A271, A272, + A273, A274, A275, A276, A277, A278, A279, A280, A281, A282, A283, A284, A285, A286, A287, A288, + A289, A290, A291, A292, A293, A294, A295, A296, A297, A298, A299, A300, A301, A302, A303, A304, + A305, A306, A307, A308, A309, A310, A311, A312, A313, A314, A315, A316, A317, A318, A319, A320, + A321, A322, A323, A324, A325, A326, A327, A328, A329, A330, A331, A332, A333, A334, A335, A336, + A337, A338, A339, A340, A341, A342, A343, A344, A345, A346, A347, A348, A349, A350, A351, A352, + A353, A354, A355, A356, A357, A358, A359, A360, A361, A362, A363, A364, A365, A366, A367, A368, + A369, A370, A371, A372, A373, A374, A375, A376, A377, A378, A379, A380, A381, A382, A383, A384, + A385, A386, A387, A388, A389, A390, A391, A392, A393, A394, A395, A396, A397, A398, A399, A400, + A401, A402, A403, A404, A405, A406, A407, A408, A409, A410, A411, A412, A413, A414, A415, A416, + A417, A418, A419, A420, A421, A422, A423, A424, A425, A426, A427, A428, A429, A430, A431, A432, + A433, A434, A435, A436, A437, A438, A439, A440, A441, A442, A443, A444, A445, A446, A447, A448, + A449, A450, A451, A452, A453, A454, A455, A456, A457, A458, A459, A460, A461, A462, A463, A464, + A465, A466, A467, A468, A469, A470, A471, A472, A473, A474, A475, A476, A477, A478, A479, A480, + A481, A482, A483, A484, A485, A486, A487, A488, A489, A490, A491, A492, A493, A494, A495, A496, + A497, A498, A499, A500, A501, A502, A503, A504, A505, A506, A507, A508, A509, A510, A511, A512, + A513, A514, A515, A516, A517, A518, A519, A520, A521, A522, A523, A524, A525, A526, A527, A528, + A529, A530, A531, A532, A533, A534, A535, A536, A537, A538, A539, A540, A541, A542, A543, A544, + A545, A546, A547, A548, A549, A550, A551, A552, A553, A554, A555, A556, A557, A558, A559, A560, + A561, A562, A563, A564, A565, A566, A567, A568, A569, A570, A571, A572, A573, A574, A575, A576, + A577, A578, A579, A580, A581, A582, A583, A584, A585, A586, A587, A588, A589, A590, A591, A592, + A593, A594, A595, A596, A597, A598, A599, A600, A601, A602, A603, A604, A605, A606, A607, A608, + A609, A610, A611, A612, A613, A614, A615, A616, A617, A618, A619, A620, A621, A622, A623, A624, + A625, A626, A627, A628, A629, A630, A631, A632, A633, A634, A635, A636, A637, A638, A639, A640, + A641, A642, A643, A644, A645, A646, A647, A648, A649, A650, A651, A652, A653, A654, A655, A656, + A657, A658, A659, A660, A661, A662, A663, A664, A665, A666, A667, A668, A669, A670, A671, A672, + A673, A674, A675, A676, A677, A678, A679, A680, A681, A682, A683, A684, A685, A686, A687, A688, + A689, A690, A691, A692, A693, A694, A695, A696, A697, A698, A699, A700, A701, A702, A703, A704, + A705, A706, A707, A708, A709, A710, A711, A712, A713, A714, A715, A716, A717, A718, A719, A720, + A721, A722, A723, A724, A725, A726, A727, A728, A729, A730, A731, A732, A733, A734, A735, A736, + A737, A738, A739, A740, A741, A742, A743, A744, A745, A746, A747, A748, A749, A750, A751, A752, + A753, A754, A755, A756, A757, A758, A759, A760, A761, A762, A763, A764, A765, A766, A767, A768, + A769, A770, A771, A772, A773, A774, A775, A776, A777, A778, A779, A780, A781, A782, A783, A784, + A785, A786, A787, A788, A789, A790, A791, A792, A793, A794, A795, A796, A797, A798, A799, A800, + A801, A802, A803, A804, A805, A806, A807, A808, A809, A810, A811, A812, A813, A814, A815, A816, + A817, A818, A819, A820, A821, A822, A823, A824, A825, A826, A827, A828, A829, A830, A831, A832, + A833, A834, A835, A836, A837, A838, A839, A840, A841, A842, A843, A844, A845, A846, A847, A848, + A849, A850, A851, A852, A853, A854, A855, A856, A857, A858, A859, A860, A861, A862, A863, A864, + A865, A866, A867, A868, A869, A870, A871, A872, A873, A874, A875, A876, A877, A878, A879, A880, + A881, A882, A883, A884, A885, A886, A887, A888, A889, A890, A891, A892, A893, A894, A895, A896, + A897, A898, A899, A900, A901, A902, A903, A904, A905, A906, A907, A908, A909, A910, A911, A912, + A913, A914, A915, A916, A917, A918, A919, A920, A921, A922, A923, A924, A925, A926, A927, A928, + A929, A930, A931, A932, A933, A934, A935, A936, A937, A938, A939, A940, A941, A942, A943, A944, + A945, A946, A947, A948, A949, A950, A951, A952, A953, A954, A955, A956, A957, A958, A959, A960, + A961, A962, A963, A964, A965, A966, A967, A968, A969, A970, A971, A972, A973, A974, A975, A976, + A977, A978, A979, A980, A981, A982, A983, A984, A985, A986, A987, A988, A989, A990, A991, A992, + A993, A994, A995, A996, A997, A998, A999 +); + +#[derive(Default)] +struct M0 { + m1: M1, + m2: M1, + m3: M1, + m4: M1, + m5: M1, + m6: M1, + m7: M1, + m8: M1, + m9: M1, + m10: M1, + m11: M1, + m12: M1, + m13: M1, + m14: M1, + m15: M1, +} + +#[derive(Default)] +struct M1 { + m1: M2, + m2: M2, + m3: M2, + m4: M2, + m5: M2, + m6: M2, + m7: M2, + m8: M2, + m9: M2, + m10: M2, + m11: M2, + m12: M2, + m13: M2, + m14: M2, + m15: M2, +} + +#[derive(Default)] +struct M2 { + m1: M3, + m2: M3, + m3: M3, + m4: M3, + m5: M3, + m6: M3, + m7: M3, + m8: M3, + m9: M3, + m10: M3, + m11: M3, + m12: M3, + m13: M3, + m14: M3, + m15: M3, +} + +#[derive(Default)] +struct M3 {} + +fn main() { + M0::default().Au(); + //~^ ERROR no method named `Au` found for struct `M0` in the current scope + M0::default().Au(); + //~^ ERROR no method named `Au` found for struct `M0` in the current scope + M0::default().Au(); + //~^ ERROR no method named `Au` found for struct `M0` in the current scope + M0::default().Au(); + //~^ ERROR no method named `Au` found for struct `M0` in the current scope + M0::default().Au(); + //~^ ERROR no method named `Au` found for struct `M0` in the current scope + M0::default().Au(); + //~^ ERROR no method named `Au` found for struct `M0` in the current scope + M0::default().Au(); + //~^ ERROR no method named `Au` found for struct `M0` in the current scope + M0::default().Au(); + //~^ ERROR no method named `Au` found for struct `M0` in the current scope + M0::default().Au(); + //~^ ERROR no method named `Au` found for struct `M0` in the current scope +} diff --git a/tests/ui/methods/probe-for-diagnostic-doesnt-do-extra-work.stderr b/tests/ui/methods/probe-for-diagnostic-doesnt-do-extra-work.stderr new file mode 100644 index 00000000000..f5c01ef8fe0 --- /dev/null +++ b/tests/ui/methods/probe-for-diagnostic-doesnt-do-extra-work.stderr @@ -0,0 +1,84 @@ +error[E0599]: no method named `Au` found for struct `M0` in the current scope + --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:145:19 + | +LL | struct M0 { + | --------- method `Au` not found for this struct +... +LL | M0::default().Au(); + | ^^ method not found in `M0` + +error[E0599]: no method named `Au` found for struct `M0` in the current scope + --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:147:19 + | +LL | struct M0 { + | --------- method `Au` not found for this struct +... +LL | M0::default().Au(); + | ^^ method not found in `M0` + +error[E0599]: no method named `Au` found for struct `M0` in the current scope + --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:149:19 + | +LL | struct M0 { + | --------- method `Au` not found for this struct +... +LL | M0::default().Au(); + | ^^ method not found in `M0` + +error[E0599]: no method named `Au` found for struct `M0` in the current scope + --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:151:19 + | +LL | struct M0 { + | --------- method `Au` not found for this struct +... +LL | M0::default().Au(); + | ^^ method not found in `M0` + +error[E0599]: no method named `Au` found for struct `M0` in the current scope + --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:153:19 + | +LL | struct M0 { + | --------- method `Au` not found for this struct +... +LL | M0::default().Au(); + | ^^ method not found in `M0` + +error[E0599]: no method named `Au` found for struct `M0` in the current scope + --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:155:19 + | +LL | struct M0 { + | --------- method `Au` not found for this struct +... +LL | M0::default().Au(); + | ^^ method not found in `M0` + +error[E0599]: no method named `Au` found for struct `M0` in the current scope + --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:157:19 + | +LL | struct M0 { + | --------- method `Au` not found for this struct +... +LL | M0::default().Au(); + | ^^ method not found in `M0` + +error[E0599]: no method named `Au` found for struct `M0` in the current scope + --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:159:19 + | +LL | struct M0 { + | --------- method `Au` not found for this struct +... +LL | M0::default().Au(); + | ^^ method not found in `M0` + +error[E0599]: no method named `Au` found for struct `M0` in the current scope + --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:161:19 + | +LL | struct M0 { + | --------- method `Au` not found for this struct +... +LL | M0::default().Au(); + | ^^ method not found in `M0` + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0599`. From dbd2ca6478dca81dc4ed64f9dec09fb216d34f1a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 7 May 2024 11:09:21 -0400 Subject: [PATCH 09/14] Use a proper probe for shadowing impl --- .../rustc_middle/src/traits/solve/inspect.rs | 2 ++ .../src/traits/solve/inspect/format.rs | 3 ++ .../src/solve/assembly/mod.rs | 19 +++++------ .../src/solve/eval_ctxt/select.rs | 3 +- .../src/solve/inspect/analyse.rs | 34 +++++++++++++------ 5 files changed, 39 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs index 2ddcb8aab25..9e944899026 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect.rs @@ -153,6 +153,8 @@ pub enum ProbeKind<'tcx> { /// do a probe to find out what projection type(s) may be used to prove that /// the source type upholds all of the target type's object bounds. UpcastProjectionCompatibility, + /// Looking for param-env candidates that satisfy the trait ref for a projection. + ShadowedEnvProbing, /// Try to unify an opaque type with an existing key in the storage. OpaqueTypeStorageLookup { result: QueryResult<'tcx> }, } diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs index e652f0586c4..5b3c50cb973 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs @@ -118,6 +118,9 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { ProbeKind::TraitCandidate { source, result } => { write!(self.f, "CANDIDATE {source:?}: {result:?}") } + ProbeKind::ShadowedEnvProbing => { + write!(self.f, "PROBING FOR IMPLS SHADOWED BY PARAM-ENV CANDIDATE:") + } }?; self.nested(|this| { diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 9a027d7f937..97bea28f06a 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -1,7 +1,7 @@ //! Code shared by trait and projection goals for candidate assembly. use crate::solve::GoalSource; -use crate::solve::{inspect, EvalCtxt, SolverMode}; +use crate::solve::{EvalCtxt, SolverMode}; use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; use rustc_middle::bug; @@ -16,7 +16,6 @@ use rustc_middle::ty::{fast_reject, TypeFoldable}; use rustc_middle::ty::{ToPredicate, TypeVisitableExt}; use rustc_span::{ErrorGuaranteed, DUMMY_SP}; use std::fmt::Debug; -use std::mem; pub(super) mod structural_traits; @@ -792,17 +791,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, G>, candidates: &mut Vec>, ) { - // HACK: We temporarily remove the `ProofTreeBuilder` to - // avoid adding `Trait` candidates to the candidates used - // to prove the current goal. - let inspect = mem::replace(&mut self.inspect, inspect::ProofTreeBuilder::new_noop()); - let tcx = self.tcx(); let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> = goal.with(tcx, goal.predicate.trait_ref(tcx)); - let mut trait_candidates_from_env = Vec::new(); - self.assemble_param_env_candidates(trait_goal, &mut trait_candidates_from_env); - self.assemble_alias_bound_candidates(trait_goal, &mut trait_candidates_from_env); + + let mut trait_candidates_from_env = vec![]; + self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| { + ecx.assemble_param_env_candidates(trait_goal, &mut trait_candidates_from_env); + ecx.assemble_alias_bound_candidates(trait_goal, &mut trait_candidates_from_env); + }); + if !trait_candidates_from_env.is_empty() { let trait_env_result = self.merge_candidates(trait_candidates_from_env); match trait_env_result.unwrap().value.certainty { @@ -831,7 +829,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } } - self.inspect = inspect; } /// If there are multiple ways to prove a trait or projection goal, we have diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs index 6fda5f4af25..68c0c8bf09e 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs @@ -176,7 +176,8 @@ fn to_selection<'tcx>( | ProbeKind::UnsizeAssembly | ProbeKind::UpcastProjectionCompatibility | ProbeKind::OpaqueTypeStorageLookup { result: _ } - | ProbeKind::Root { result: _ } => { + | ProbeKind::Root { result: _ } + | ProbeKind::ShadowedEnvProbing => { span_bug!(span, "didn't expect to assemble trait candidate from {:#?}", cand.kind()) } }) diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index fd36b7ffd4e..b71a1b339cb 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -18,8 +18,8 @@ use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{inspect, QueryResult}; use rustc_middle::traits::solve::{Certainty, Goal}; use rustc_middle::traits::ObligationCause; -use rustc_middle::ty; use rustc_middle::ty::TypeFoldable; +use rustc_middle::{bug, ty}; use rustc_span::{Span, DUMMY_SP}; use crate::solve::eval_ctxt::canonical; @@ -290,12 +290,25 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { match *step { inspect::ProbeStep::AddGoal(source, goal) => nested_goals.push((source, goal)), inspect::ProbeStep::NestedProbe(ref probe) => { - // Nested probes have to prove goals added in their parent - // but do not leak them, so we truncate the added goals - // afterwards. - let num_goals = nested_goals.len(); - self.candidates_recur(candidates, nested_goals, probe); - nested_goals.truncate(num_goals); + match probe.kind { + // These never assemble candidates for the goal we're trying to solve. + inspect::ProbeKind::UpcastProjectionCompatibility + | inspect::ProbeKind::ShadowedEnvProbing => continue, + + inspect::ProbeKind::NormalizedSelfTyAssembly + | inspect::ProbeKind::UnsizeAssembly + | inspect::ProbeKind::Root { .. } + | inspect::ProbeKind::TryNormalizeNonRigid { .. } + | inspect::ProbeKind::TraitCandidate { .. } + | inspect::ProbeKind::OpaqueTypeStorageLookup { .. } => { + // Nested probes have to prove goals added in their parent + // but do not leak them, so we truncate the added goals + // afterwards. + let num_goals = nested_goals.len(); + self.candidates_recur(candidates, nested_goals, probe); + nested_goals.truncate(num_goals); + } + } } inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => { assert_eq!(shallow_certainty.replace(c), None); @@ -308,9 +321,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { } match probe.kind { - inspect::ProbeKind::NormalizedSelfTyAssembly - | inspect::ProbeKind::UnsizeAssembly - | inspect::ProbeKind::UpcastProjectionCompatibility => (), + inspect::ProbeKind::UpcastProjectionCompatibility + | inspect::ProbeKind::ShadowedEnvProbing => bug!(), + + inspect::ProbeKind::NormalizedSelfTyAssembly | inspect::ProbeKind::UnsizeAssembly => {} // We add a candidate even for the root evaluation if there // is only one way to prove a given goal, e.g. for `WellFormed`. From 57c32a193fee197f7ad034210de005db338a64ec Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 10 Jan 2024 19:30:22 -0800 Subject: [PATCH 10/14] style-guide: When breaking binops handle multi-line first operand better Use the indentation of the *last* line of the first operand, not the first. Fixes https://github.com/rust-lang/style-team/issues/189 --- src/doc/style-guide/src/editions.md | 2 ++ src/doc/style-guide/src/expressions.md | 31 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/doc/style-guide/src/editions.md b/src/doc/style-guide/src/editions.md index 9d593f80810..74e873e35ff 100644 --- a/src/doc/style-guide/src/editions.md +++ b/src/doc/style-guide/src/editions.md @@ -40,6 +40,8 @@ include: of a delimited expression, delimited expressions are generally combinable, regardless of the number of members. Previously only applied with exactly one member (except for closures with explicit blocks). +- When line-breaking a binary operator, if the first operand spans multiple + lines, use the base indentation of the last line. - Miscellaneous `rustfmt` bugfixes. - Use version-sort (sort `x8`, `x16`, `x32`, `x64`, `x128` in that order). - Change "ASCIIbetical" sort to Unicode-aware "non-lowercase before lowercase". diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md index 171a24cd89d..597f8fcaf40 100644 --- a/src/doc/style-guide/src/expressions.md +++ b/src/doc/style-guide/src/expressions.md @@ -328,6 +328,37 @@ foo_bar Prefer line-breaking at an assignment operator (either `=` or `+=`, etc.) rather than at other binary operators. +If line-breaking a binary operator (including assignment operators) where the +first operand spans multiple lines, use the base indentation of the *last* +line of the first , and indent relative to that: + +```rust +impl SomeType { + fn method(&mut self) { + self.array[array_index as usize] + .as_mut() + .expect("thing must exist") + .extra_info = + long_long_long_long_long_long_long_long_long_long_long_long_long_long_long; + + self.array[array_index as usize] + .as_mut() + .expect("thing must exist") + .extra_info + + long_long_long_long_long_long_long_long_long_long_long_long_long_long_long; + + self.array[array_index as usize] + .as_mut() + .expect("thing must exist") + .extra_info = Some(ExtraInfo { + parent, + count: count as u16, + children: children.into_boxed_slice(), + }); + } +} +``` + ### Casts (`as`) Format `as` casts like a binary operator. In particular, always include spaces From e2d9c0d938a057dfe745dea4a38eb397b6feb3c1 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 20 Jan 2024 13:26:01 -0800 Subject: [PATCH 11/14] Fix missing word Co-authored-by: Caleb Cartwright --- src/doc/style-guide/src/expressions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md index 597f8fcaf40..221cb3fbcc3 100644 --- a/src/doc/style-guide/src/expressions.md +++ b/src/doc/style-guide/src/expressions.md @@ -330,7 +330,7 @@ than at other binary operators. If line-breaking a binary operator (including assignment operators) where the first operand spans multiple lines, use the base indentation of the *last* -line of the first , and indent relative to that: +line of the first operand, and indent relative to that: ```rust impl SomeType { From e098eb14ae9576593b38d4179c981fb7af7bee89 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 20 Jan 2024 13:26:26 -0800 Subject: [PATCH 12/14] Wording improvement Co-authored-by: Caleb Cartwright --- src/doc/style-guide/src/expressions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md index 221cb3fbcc3..3bb0ee6d5ff 100644 --- a/src/doc/style-guide/src/expressions.md +++ b/src/doc/style-guide/src/expressions.md @@ -328,7 +328,7 @@ foo_bar Prefer line-breaking at an assignment operator (either `=` or `+=`, etc.) rather than at other binary operators. -If line-breaking a binary operator (including assignment operators) where the +If line-breaking at a binary operator (including assignment operators) where the first operand spans multiple lines, use the base indentation of the *last* line of the first operand, and indent relative to that: From f97d9151733ae29aa7d530a385003282b549dafc Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 14 May 2024 13:39:40 +0200 Subject: [PATCH 13/14] Use new utility functions/methods in run-make tests --- tests/run-make/doctests-keep-binaries/rmake.rs | 9 +++------ tests/run-make/doctests-runtool/rmake.rs | 3 +-- tests/run-make/rustdoc-map-file/rmake.rs | 6 ++---- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/tests/run-make/doctests-keep-binaries/rmake.rs b/tests/run-make/doctests-keep-binaries/rmake.rs index ad0c2764df7..0613ef4839b 100644 --- a/tests/run-make/doctests-keep-binaries/rmake.rs +++ b/tests/run-make/doctests-keep-binaries/rmake.rs @@ -26,8 +26,7 @@ fn main() { .arg("--test") .arg("--persist-doctests") .arg(out_dir) - .arg("--extern") - .arg(format!("t={}", extern_path.display())) + .extern_("t", extern_path) .run(); check_generated_binaries(); }); @@ -38,8 +37,7 @@ fn main() { .arg("--test") .arg("--persist-doctests") .arg(out_dir) - .arg("--extern") - .arg(format!("t={}", extern_path.display())) + .extern_("t", extern_path) .arg("--no-run") .run(); check_generated_binaries(); @@ -59,8 +57,7 @@ fn main() { .arg("doctests") .arg("--test-run-directory") .arg(run_dir) - .arg("--extern") - .arg("t=libt.rlib") + .extern_("t", "libt.rlib") .run(); remove_dir_all(run_dir_path); diff --git a/tests/run-make/doctests-runtool/rmake.rs b/tests/run-make/doctests-runtool/rmake.rs index 6f89bf23b47..6cc7c6bbdaf 100644 --- a/tests/run-make/doctests-runtool/rmake.rs +++ b/tests/run-make/doctests-runtool/rmake.rs @@ -29,8 +29,7 @@ fn main() { .arg(run_dir_name) .arg("--runtool") .arg(&run_tool_binary) - .arg("--extern") - .arg("t=libt.rlib") + .extern_("t", "libt.rlib") .current_dir(tmp_dir()) .run(); diff --git a/tests/run-make/rustdoc-map-file/rmake.rs b/tests/run-make/rustdoc-map-file/rmake.rs index aaa7fea0b6b..d017b41bcdd 100644 --- a/tests/run-make/rustdoc-map-file/rmake.rs +++ b/tests/run-make/rustdoc-map-file/rmake.rs @@ -1,5 +1,4 @@ -use run_make_support::{rustdoc, tmp_dir}; -use std::process::Command; +use run_make_support::{python_command, rustdoc, tmp_dir}; fn main() { let out_dir = tmp_dir().join("out"); @@ -10,6 +9,5 @@ fn main() { .output(&out_dir) .run(); // FIXME (GuillaumeGomez): Port the python script to Rust as well. - let python = std::env::var("PYTHON").unwrap_or("python".into()); - assert!(Command::new(python).arg("validate_json.py").arg(&out_dir).status().unwrap().success()); + assert!(python_command().arg("validate_json.py").arg(&out_dir).status().unwrap().success()); } From ade33b02f237d484bef950ebf550bc12d49313d1 Mon Sep 17 00:00:00 2001 From: bohan Date: Mon, 13 May 2024 22:57:44 +0800 Subject: [PATCH 14/14] only find segs chain for missing methods when no available candidates --- .../rustc_hir_typeck/src/method/suggest.rs | 39 ++++++++++++++++--- tests/ui/const-generics/lookup-method.rs | 19 +++++++++ tests/ui/const-generics/lookup-method.stderr | 15 +++++++ 3 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 tests/ui/const-generics/lookup-method.rs create mode 100644 tests/ui/const-generics/lookup-method.stderr diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index d50e9943384..5b15b3c8cce 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1143,7 +1143,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let label_span_not_found = |err: &mut Diag<'_>| { + let mut find_candidate_for_method = false; + + let mut label_span_not_found = |err: &mut Diag<'_>| { if unsatisfied_predicates.is_empty() { err.span_label(span, format!("{item_kind} not found in `{ty_str}`")); let is_string_or_ref_str = match rcvr_ty.kind() { @@ -1219,6 +1221,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.note(format!( "the {item_kind} was found for\n{type_candidates}{additional_types}" )); + find_candidate_for_method = mode == Mode::MethodCall; } } } else { @@ -1371,9 +1374,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } } - // If an appropriate error source is not found, check method chain for possible candiates - if unsatisfied_predicates.is_empty() - && let Mode::MethodCall = mode + + if !find_candidate_for_method { + self.lookup_segments_chain_for_no_match_method( + &mut err, + item_name, + item_kind, + source, + no_match_data, + ); + } + + self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected); + Some(err) + } + + /// If an appropriate error source is not found, check method chain for possible candidates + fn lookup_segments_chain_for_no_match_method( + &self, + err: &mut Diag<'_>, + item_name: Ident, + item_kind: &str, + source: SelfSource<'tcx>, + no_match_data: &NoMatchData<'tcx>, + ) { + if no_match_data.unsatisfied_predicates.is_empty() + && let Mode::MethodCall = no_match_data.mode && let SelfSource::MethodCall(mut source_expr) = source { let mut stack_methods = vec![]; @@ -1394,6 +1420,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .unwrap_or(Ty::new_misc_error(self.tcx)), ); + // FIXME: `probe_for_name_many` searches for methods in inherent implementations, + // so it may return a candidate that doesn't belong to this `revr_ty`. We need to + // check whether the instantiated type matches the received one. for _matched_method in self.probe_for_name_many( Mode::MethodCall, item_name, @@ -1416,8 +1445,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } } - self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected); - Some(err) } fn find_likely_intended_associated_item( diff --git a/tests/ui/const-generics/lookup-method.rs b/tests/ui/const-generics/lookup-method.rs new file mode 100644 index 00000000000..915935c94a5 --- /dev/null +++ b/tests/ui/const-generics/lookup-method.rs @@ -0,0 +1,19 @@ +// https://github.com/rust-lang/rust/issues/124946 + +struct Builder; + +impl Builder { + fn cast(self) -> Builder { + Builder + } +} + +impl Builder { + fn build(self) {} +} + +fn main() { + let b = Builder::; + b.cast().build(); + //~^ ERROR: no method named `build` found for struct `Builder` in the current scope +} diff --git a/tests/ui/const-generics/lookup-method.stderr b/tests/ui/const-generics/lookup-method.stderr new file mode 100644 index 00000000000..4cbd1e17c7b --- /dev/null +++ b/tests/ui/const-generics/lookup-method.stderr @@ -0,0 +1,15 @@ +error[E0599]: no method named `build` found for struct `Builder` in the current scope + --> $DIR/lookup-method.rs:17:14 + | +LL | struct Builder; + | -------------------------------------------- method `build` not found for this struct +... +LL | b.cast().build(); + | ^^^^^ method not found in `Builder` + | + = note: the method was found for + - `Builder` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`.