diff options
| author | Ralf Jung <post@ralfj.de> | 2023-06-22 10:39:19 +0200 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2023-06-22 10:39:19 +0200 |
| commit | 940cd59e39ce06bcacda3d342b97f28761555ba5 (patch) | |
| tree | 8b2cc6943f54a3a3d4dab4ca9fd6c8a899543427 | |
| parent | 2bd9ade66e28a1fa5c6609d12cd8461cfa36d809 (diff) | |
| parent | 0faea7728f283dca5693f79be7615f67842c55dd (diff) | |
| download | rust-940cd59e39ce06bcacda3d342b97f28761555ba5.tar.gz rust-940cd59e39ce06bcacda3d342b97f28761555ba5.zip | |
Merge from rustc
820 files changed, 14550 insertions, 6034 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 398a70ee6a2..2f54d2838cf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -417,30 +417,16 @@ jobs: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstate/toolstates.json" DEPLOY_TOOLSTATES_JSON: toolstates-windows.json os: windows-2019-8core-32gb - - name: i686-mingw-1 + - name: i686-mingw env: RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu" - SCRIPT: make ci-mingw-subset-1 + SCRIPT: make ci-mingw NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 os: windows-2019-8core-32gb - - name: i686-mingw-2 + - name: x86_64-mingw env: - RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu" - SCRIPT: make ci-mingw-subset-2 - NO_DOWNLOAD_CI_LLVM: 1 - CUSTOM_MINGW: 1 - os: windows-2019-8core-32gb - - name: x86_64-mingw-1 - env: - SCRIPT: make ci-mingw-subset-1 - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler" - NO_DOWNLOAD_CI_LLVM: 1 - CUSTOM_MINGW: 1 - os: windows-2019-8core-32gb - - name: x86_64-mingw-2 - env: - SCRIPT: make ci-mingw-subset-2 + SCRIPT: make ci-mingw RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler" NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 diff --git a/Cargo.lock b/Cargo.lock index 4eafda94037..28db4063996 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -360,7 +360,7 @@ dependencies = [ name = "cargo-miri" version = "0.1.0" dependencies = [ - "cargo_metadata 0.15.3", + "cargo_metadata", "directories", "rustc-build-sysroot", "rustc-workspace-hack", @@ -381,22 +381,9 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c297bd3135f558552f99a0daa180876984ea2c4ffa7470314540dff8c654109a" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", -] - -[[package]] -name = "cargo_metadata" -version = "0.15.3" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a1ec454bc3eead8719cb56e15dbbfecdbc14e4b3a3ae4936cc6e31f5fc0d07" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" dependencies = [ "camino", "cargo-platform", @@ -631,7 +618,7 @@ name = "clippy_lints" version = "0.1.72" dependencies = [ "arrayvec", - "cargo_metadata 0.15.3", + "cargo_metadata", "clippy_utils", "declare_clippy_lint", "if_chain", @@ -710,9 +697,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.92" +version = "0.1.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64518f1ae689f74db058bbfb3238dfe6eb53f59f4ae712f1ff4348628522e190" +checksum = "76630810d973ecea3dbf611e1b7aecfb1012751ef1ff8de3998f89014a166781" dependencies = [ "cc", "rustc-std-workspace-core", @@ -4348,35 +4335,33 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 1.0.102", + "syn 2.0.8", ] [[package]] name = "rustfmt-nightly" -version = "1.5.2" +version = "1.5.3" dependencies = [ "annotate-snippets", "anyhow", "bytecount", - "cargo_metadata 0.14.0", - "clap 3.2.20", - "derive-new", + "cargo_metadata", + "clap 4.2.1", "diff", "dirs", - "env_logger 0.9.0", + "env_logger 0.10.0", "getopts", "ignore", "itertools", "lazy_static", "log", "regex", - "rustc-workspace-hack", "rustfmt-config_proc_macro", "serde", "serde_json", "term", "thiserror", - "toml 0.5.7", + "toml 0.7.4", "unicode-segmentation", "unicode-width", "unicode_categories", @@ -4956,7 +4941,7 @@ name = "tidy" version = "0.1.0" dependencies = [ "cargo-platform", - "cargo_metadata 0.15.3", + "cargo_metadata", "ignore", "lazy_static", "miropt-test-tools", @@ -5192,7 +5177,7 @@ checksum = "191a442639ea102fa62671026047e51d574bfda44b7fdf32151d7314624c1cd2" dependencies = [ "bstr", "cargo-platform", - "cargo_metadata 0.15.3", + "cargo_metadata", "color-eyre", "colored", "crossbeam-channel", diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 4360fbeb9bb..a398fd80119 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1295,6 +1295,7 @@ impl Expr { ExprKind::Yield(..) => ExprPrecedence::Yield, ExprKind::Yeet(..) => ExprPrecedence::Yeet, ExprKind::FormatArgs(..) => ExprPrecedence::FormatArgs, + ExprKind::Become(..) => ExprPrecedence::Become, ExprKind::Err => ExprPrecedence::Err, } } @@ -1515,6 +1516,11 @@ pub enum ExprKind { /// with an optional value to be returned. Yeet(Option<P<Expr>>), + /// A tail call return, with the value to be returned. + /// + /// While `.0` must be a function call, we check this later, after parsing. + Become(P<Expr>), + /// Bytes included via `include_bytes!` /// Added for optimization purposes to avoid the need to escape /// large binary blobs - should always behave like [`ExprKind::Lit`] diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 66b94d12a32..53a9c9a046e 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1457,6 +1457,7 @@ pub fn noop_visit_expr<T: MutVisitor>( ExprKind::Yeet(expr) => { visit_opt(expr, |expr| vis.visit_expr(expr)); } + ExprKind::Become(expr) => vis.visit_expr(expr), ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm), ExprKind::FormatArgs(fmt) => vis.visit_format_args(fmt), ExprKind::OffsetOf(container, fields) => { diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 35afd542372..096077e09bf 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -245,6 +245,7 @@ pub enum ExprPrecedence { Ret, Yield, Yeet, + Become, Range, @@ -298,7 +299,8 @@ impl ExprPrecedence { | ExprPrecedence::Continue | ExprPrecedence::Ret | ExprPrecedence::Yield - | ExprPrecedence::Yeet => PREC_JUMP, + | ExprPrecedence::Yeet + | ExprPrecedence::Become => PREC_JUMP, // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to // parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 275692ad5dd..d9de5b8e197 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -908,6 +908,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::Yeet(optional_expression) => { walk_list!(visitor, visit_expr, optional_expression); } + ExprKind::Become(expr) => visitor.visit_expr(expr), ExprKind::MacCall(mac) => visitor.visit_mac_call(mac), ExprKind::Paren(subexpression) => visitor.visit_expr(subexpression), ExprKind::InlineAsm(asm) => visitor.visit_inline_asm(asm), diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index f52797c4f3f..225714a1361 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -275,6 +275,12 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ExprKind::Ret(e) } ExprKind::Yeet(sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()), + ExprKind::Become(sub_expr) => { + let sub_expr = self.lower_expr(sub_expr); + + // FIXME(explicit_tail_calls): Use `hir::ExprKind::Become` once we implemented it + hir::ExprKind::Ret(Some(sub_expr)) + } ExprKind::InlineAsm(asm) => { hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm)) } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 2125349909e..b0dbc2c2340 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -555,6 +555,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(dyn_star, "`dyn*` trait objects are experimental"); gate_all!(const_closures, "const closures are experimental"); gate_all!(builtin_syntax, "`builtin #` syntax is unstable"); + gate_all!(explicit_tail_calls, "`become` expression is experimental"); if !visitor.features.negative_bounds { for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 87c32ffce12..609920180a2 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -537,6 +537,11 @@ impl<'a> State<'a> { self.print_expr_maybe_paren(expr, parser::PREC_JUMP); } } + ast::ExprKind::Become(result) => { + self.word("become"); + self.word(" "); + self.print_expr_maybe_paren(result, parser::PREC_JUMP); + } ast::ExprKind::InlineAsm(a) => { // FIXME: This should have its own syntax, distinct from a macro invocation. self.word("asm!"); diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index 6be20b0974d..0b44beeb004 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -72,8 +72,11 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> { let kind = match self.kind { mir::BorrowKind::Shared => "", mir::BorrowKind::Shallow => "shallow ", - mir::BorrowKind::Unique => "uniq ", - mir::BorrowKind::Mut { .. } => "mut ", + mir::BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } => "uniq ", + // FIXME: differentiate `TwoPhaseBorrow` + mir::BorrowKind::Mut { + kind: mir::MutBorrowKind::Default | mir::MutBorrowKind::TwoPhaseBorrow, + } => "mut ", }; write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place) } diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index acca1a1477f..a4e0e773a81 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -278,7 +278,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { move_from_span: Span, move_from_desc: &str, ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { - struct_span_err!(self, move_from_span, E0507, "cannot move out of {}", move_from_desc,) + struct_span_err!(self, move_from_span, E0507, "cannot move out of {}", move_from_desc) } /// Signal an error due to an attempt to move out of the interior diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 15d73ed732f..5c365e98f0b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -14,9 +14,10 @@ use rustc_infer::traits::ObligationCause; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ - self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, - FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, - ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm, + self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory, + FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind, Operand, Place, + PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, + VarBindingForm, }; use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty}; use rustc_middle::util::CallKind; @@ -678,7 +679,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Find out if the predicates show that the type is a Fn or FnMut let find_fn_kind_from_did = |(pred, _): (ty::Predicate<'tcx>, _)| { - if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred.kind().skip_binder() + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = pred.kind().skip_binder() && pred.self_ty() == ty { if Some(pred.def_id()) == tcx.lang_items().fn_trait() { @@ -704,7 +705,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx .explicit_item_bounds(def_id) .subst_iter_copied(tcx, substs) - .find_map(find_fn_kind_from_did), + .find_map(|(clause, span)| find_fn_kind_from_did((clause.as_predicate(), span))), ty::Closure(_, substs) => match substs.as_closure().kind() { ty::ClosureKind::Fn => Some(hir::Mutability::Not), ty::ClosureKind::FnMut => Some(hir::Mutability::Mut), @@ -775,7 +776,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let predicates: Result<Vec<_>, _> = errors .into_iter() .map(|err| match err.obligation.predicate.kind().skip_binder() { - PredicateKind::Clause(ty::Clause::Trait(predicate)) => { + PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { match predicate.self_ty().kind() { ty::Param(param_ty) => Ok(( generics.type_param(param_ty, tcx), @@ -926,7 +927,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // FIXME: supply non-"" `opt_via` when appropriate let first_borrow_desc; let mut err = match (gen_borrow_kind, issued_borrow.kind) { - (BorrowKind::Shared, BorrowKind::Mut { .. }) => { + ( + BorrowKind::Shared, + BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, + ) => { first_borrow_desc = "mutable "; self.cannot_reborrow_already_borrowed( span, @@ -940,7 +944,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { None, ) } - (BorrowKind::Mut { .. }, BorrowKind::Shared) => { + ( + BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, + BorrowKind::Shared, + ) => { first_borrow_desc = "immutable "; let mut err = self.cannot_reborrow_already_borrowed( span, @@ -962,7 +969,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err } - (BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => { + ( + BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, + BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, + ) => { first_borrow_desc = "first "; let mut err = self.cannot_mutably_borrow_multiply( span, @@ -985,12 +995,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err } - (BorrowKind::Unique, BorrowKind::Unique) => { + ( + BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, + BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, + ) => { first_borrow_desc = "first "; self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None) } - (BorrowKind::Mut { .. } | BorrowKind::Unique, BorrowKind::Shallow) => { + (BorrowKind::Mut { .. }, BorrowKind::Shallow) => { if let Some(immutable_section_description) = self.classify_immutable_section(issued_borrow.assigned_place) { @@ -1004,7 +1017,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow_spans.var_subdiag( None, &mut err, - Some(BorrowKind::Unique), + Some(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }), |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; match kind { @@ -1038,7 +1051,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - (BorrowKind::Unique, _) => { + (BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, _) => { first_borrow_desc = "first "; self.cannot_uniquely_borrow_by_one_closure( span, @@ -1052,7 +1065,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) } - (BorrowKind::Shared, BorrowKind::Unique) => { + (BorrowKind::Shared, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => { first_borrow_desc = "first "; self.cannot_reborrow_already_uniquely_borrowed( span, @@ -1067,7 +1080,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) } - (BorrowKind::Mut { .. }, BorrowKind::Unique) => { + (BorrowKind::Mut { .. }, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => { first_borrow_desc = "first "; self.cannot_reborrow_already_uniquely_borrowed( span, @@ -1085,10 +1098,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { (BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Shallow) | ( BorrowKind::Shallow, - BorrowKind::Mut { .. } - | BorrowKind::Unique - | BorrowKind::Shared - | BorrowKind::Shallow, + BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow, ) => unreachable!(), }; @@ -2579,7 +2589,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut Diagnostic) { let tcx = self.infcx.tcx; if let ( - Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }), + Some(Terminator { + kind: TerminatorKind::Call { call_source: CallSource::OverloadedOperator, .. }, + .. + }), Some((method_did, method_substs)), ) = ( &self.body[loan.reserve_location.block].terminator, diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 1d430a93a87..6c01fd63b1e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -6,8 +6,8 @@ use rustc_hir::intravisit::Visitor; use rustc_index::IndexSlice; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::mir::{ - Body, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location, Operand, Place, - Rvalue, Statement, StatementKind, TerminatorKind, + Body, CallSource, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location, + Operand, Place, Rvalue, Statement, StatementKind, TerminatorKind, }; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::{self, RegionVid, TyCtxt}; @@ -494,7 +494,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } else if self.was_captured_by_trait_object(borrow) { LaterUseKind::TraitCapture } else if location.statement_index == block.statements.len() { - if let TerminatorKind::Call { func, from_hir_call: true, .. } = + if let TerminatorKind::Call { func, call_source: CallSource::Normal, .. } = &block.terminator().kind { // Just point to the function, to reduce the chance of overlapping spans. diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 20370e4c6ac..2f8c970f806 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -13,8 +13,9 @@ use rustc_index::IndexSlice; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ - AggregateKind, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location, Operand, Place, - PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, + AggregateKind, CallSource, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location, + Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, + TerminatorKind, }; use rustc_middle::ty::print::Print; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; @@ -414,7 +415,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if !is_terminator { continue; } else if let Some(Terminator { - kind: TerminatorKind::Call { func, from_hir_call: false, .. }, + kind: + TerminatorKind::Call { + func, + call_source: CallSource::OverloadedOperator, + .. + }, .. }) = &bbd.terminator { @@ -622,8 +628,7 @@ impl UseSpans<'_> { err.subdiagnostic(match kind { Some(kd) => match kd { rustc_middle::mir::BorrowKind::Shared - | rustc_middle::mir::BorrowKind::Shallow - | rustc_middle::mir::BorrowKind::Unique => { + | rustc_middle::mir::BorrowKind::Shallow => { CaptureVarKind::Immut { kind_span: capture_kind_span } } @@ -839,7 +844,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("move_spans: target_temp = {:?}", target_temp); if let Some(Terminator { - kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, .. + kind: TerminatorKind::Call { fn_span, call_source, .. }, .. }) = &self.body[location.block].terminator { let Some((method_did, method_substs)) = @@ -859,7 +864,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { method_did, method_substs, *fn_span, - *from_hir_call, + call_source.from_hir_call(), Some(self.infcx.tcx.fn_arg_names(method_did)[0]), ); diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 34d466db2b4..1ba490e9a01 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -234,7 +234,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { borrow_spans.var_subdiag( None, &mut err, - Some(mir::BorrowKind::Mut { allow_two_phase_borrow: false }), + Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }), |_kind, var_span| { let place = self.describe_any_place(access_place.as_ref()); crate::session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure { @@ -300,7 +300,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { _, mir::Rvalue::Ref( _, - mir::BorrowKind::Mut { allow_two_phase_borrow: false }, + mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }, _, ), )), diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index f38e1605fa5..55c9864af8c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -939,8 +939,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { { predicates.iter().any(|pred| { match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) if data.self_ty() == ty => {} - ty::PredicateKind::Clause(ty::Clause::Projection(data)) if data.projection_ty.self_ty() == ty => {} + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) if data.self_ty() == ty => {} + ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) if data.projection_ty.self_ty() == ty => {} _ => return false, } tcx.any_free_region_meets(pred, |r| { diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index b2ff25ecb96..0152d89eb83 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -128,7 +128,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { destination, target: _, unwind: _, - from_hir_call: _, + call_source: _, fn_span: _, } => { self.consume_operand(location, func); @@ -255,7 +255,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk))) } BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), - BorrowKind::Unique | BorrowKind::Mut { .. } => { + BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); if allow_two_phase_borrow(bk) { (Deep, Reservation(wk)) @@ -273,7 +273,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { Mutability::Mut => ( Deep, Write(WriteKind::MutableBorrow(BorrowKind::Mut { - allow_two_phase_borrow: false, + kind: mir::MutBorrowKind::Default, })), ), Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))), @@ -376,14 +376,11 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { } (Read(_), BorrowKind::Shallow | BorrowKind::Shared) - | ( - Read(ReadKind::Borrow(BorrowKind::Shallow)), - BorrowKind::Unique | BorrowKind::Mut { .. }, - ) => { + | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => { // Reads don't invalidate shared or shallow borrows } - (Read(_), BorrowKind::Unique | BorrowKind::Mut { .. }) => { + (Read(_), BorrowKind::Mut { .. }) => { // Reading from mere reservations of mutable-borrows is OK. if !is_active(&this.dominators, borrow, location) { // If the borrow isn't active yet, reads don't invalidate it @@ -425,7 +422,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { // only mutable borrows should be 2-phase assert!(match borrow.kind { BorrowKind::Shared | BorrowKind::Shallow => false, - BorrowKind::Unique | BorrowKind::Mut { .. } => true, + BorrowKind::Mut { .. } => true, }); self.access_place( diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 99a988f2c62..be3a3b77797 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -29,8 +29,8 @@ use rustc_infer::infer::{ InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt, }; use rustc_middle::mir::{ - traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand, - Place, PlaceElem, PlaceRef, VarDebugInfoContents, + traversal, Body, ClearCrossCrate, Local, Location, MutBorrowKind, Mutability, + NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, VarDebugInfoContents, }; use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; @@ -710,7 +710,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro destination, target: _, unwind: _, - from_hir_call: _, + call_source: _, fn_span: _, } => { self.consume_operand(loc, (func, span), flow_state); @@ -1071,10 +1071,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } (Read(_), BorrowKind::Shared | BorrowKind::Shallow) - | ( - Read(ReadKind::Borrow(BorrowKind::Shallow)), - BorrowKind::Unique | BorrowKind::Mut { .. }, - ) => Control::Continue, + | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => { + Control::Continue + } (Reservation(_), BorrowKind::Shallow | BorrowKind::Shared) => { // This used to be a future compatibility warning (to be @@ -1087,7 +1086,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Control::Continue } - (Read(kind), BorrowKind::Unique | BorrowKind::Mut { .. }) => { + (Read(kind), BorrowKind::Mut { .. }) => { // Reading from mere reservations of mutable-borrows is OK. if !is_active(this.dominators(), borrow, location) { assert!(allow_two_phase_borrow(borrow.kind)); @@ -1194,7 +1193,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk))) } BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), - BorrowKind::Unique | BorrowKind::Mut { .. } => { + BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); if allow_two_phase_borrow(bk) { (Deep, Reservation(wk)) @@ -1231,7 +1230,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Mutability::Mut => ( Deep, Write(WriteKind::MutableBorrow(BorrowKind::Mut { - allow_two_phase_borrow: false, + kind: MutBorrowKind::Default, })), ), Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))), @@ -1565,7 +1564,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // only mutable borrows should be 2-phase assert!(match borrow.kind { BorrowKind::Shared | BorrowKind::Shallow => false, - BorrowKind::Unique | BorrowKind::Mut { .. } => true, + BorrowKind::Mut { .. } => true, }); self.access_place( @@ -1959,16 +1958,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let the_place_err; match kind { - Reservation(WriteKind::MutableBorrow( - borrow_kind @ (BorrowKind::Unique | BorrowKind::Mut { .. }), - )) - | Write(WriteKind::MutableBorrow( - borrow_kind @ (BorrowKind::Unique | BorrowKind::Mut { .. }), - )) => { - let is_local_mutation_allowed = match borrow_kind { - BorrowKind::Unique => LocalMutationIsAllowed::Yes, - BorrowKind::Mut { .. } => is_local_mutation_allowed, - BorrowKind::Shared | BorrowKind::Shallow => unreachable!(), + Reservation(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) + | Write(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) => { + let is_local_mutation_allowed = match mut_borrow_kind { + // `ClosureCapture` is used for mutable variable with a immutable binding. + // This is only behaviour difference between `ClosureCapture` and mutable borrows. + MutBorrowKind::ClosureCapture => LocalMutationIsAllowed::Yes, + MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow => { + is_local_mutation_allowed + } }; match self.is_mutable(place.as_ref(), is_local_mutation_allowed) { Ok(root_place) => { @@ -2031,12 +2029,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return false; } Read( - ReadKind::Borrow( - BorrowKind::Unique - | BorrowKind::Mut { .. } - | BorrowKind::Shared - | BorrowKind::Shallow, - ) + ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow) | ReadKind::Copy, ) => { // Access authorized diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index 25c485b814f..c83d045a94e 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -4,7 +4,9 @@ use crate::ArtificialField; use crate::Overlap; use crate::{AccessDepth, Deep, Shallow}; use rustc_hir as hir; -use rustc_middle::mir::{Body, BorrowKind, Local, Place, PlaceElem, PlaceRef, ProjectionElem}; +use rustc_middle::mir::{ + Body, BorrowKind, Local, MutBorrowKind, Place, PlaceElem, PlaceRef, ProjectionElem, +}; use rustc_middle::ty::{self, TyCtxt}; use std::cmp::max; use std::iter; @@ -35,7 +37,7 @@ pub fn places_conflict<'tcx>( tcx, body, borrow_place, - BorrowKind::Mut { allow_two_phase_borrow: true }, + BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow }, access_place.as_ref(), AccessDepth::Deep, bias, diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 6ca702cfdfc..4a872eb251c 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -330,8 +330,9 @@ fn check_opaque_type_well_formed<'tcx>( // Require the hidden type to be well-formed with only the generics of the opaque type. // Defining use functions may have more bounds than the opaque type, which is ok, as long as the // hidden type is well formed even without those bounds. - let predicate = - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(definition_ty.into()))); + let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( + definition_ty.into(), + ))); ocx.register_obligation(Obligation::misc(tcx, definition_span, def_id, param_env, predicate)); // Check that all obligations are satisfied by the implementation's diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index f527eee7bda..c19fbf20ca5 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -89,11 +89,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { category: ConstraintCategory<'tcx>, ) { self.prove_predicate( - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { - trait_ref, - constness: ty::BoundConstness::NotConst, - polarity: ty::ImplPolarity::Positive, - }))), + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Trait( + ty::TraitPredicate { + trait_ref, + constness: ty::BoundConstness::NotConst, + polarity: ty::ImplPolarity::Positive, + }, + ))), locations, category, ); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 33f75437478..0a897272d35 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1065,7 +1065,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { )?; ocx.infcx.add_item_bounds_for_hidden_type( - opaque_type_key, + opaque_type_key.def_id.to_def_id(), + opaque_type_key.substs, cause, param_env, hidden_ty.ty, @@ -1370,7 +1371,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } // FIXME: check the values } - TerminatorKind::Call { func, args, destination, from_hir_call, target, .. } => { + TerminatorKind::Call { func, args, destination, call_source, target, .. } => { self.check_operand(func, term_location); for arg in args { self.check_operand(arg, term_location); @@ -1420,7 +1421,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // See #91068 for an example. self.prove_predicates( sig.inputs_and_output.iter().map(|ty| { - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed( + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( ty.into(), ))) }), @@ -1446,7 +1447,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .add_element(region_vid, term_location); } - self.check_call_inputs(body, term, &sig, args, term_location, *from_hir_call); + self.check_call_inputs(body, term, &sig, args, term_location, *call_source); } TerminatorKind::Assert { cond, msg, .. } => { self.check_operand(cond, term_location); @@ -1573,7 +1574,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { sig: &ty::FnSig<'tcx>, args: &[Operand<'tcx>], term_location: Location, - from_hir_call: bool, + call_source: CallSource, ) { debug!("check_call_inputs({:?}, {:?})", sig, args); if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) { @@ -1591,7 +1592,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let op_arg_ty = op_arg.ty(body, self.tcx()); let op_arg_ty = self.normalize(op_arg_ty, term_location); - let category = if from_hir_call { + let category = if call_source.from_hir_call() { ConstraintCategory::CallArgument(self.infcx.tcx.erase_regions(func_ty)) } else { ConstraintCategory::Boring @@ -1852,7 +1853,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let array_ty = rvalue.ty(body.local_decls(), tcx); self.prove_predicate( - ty::PredicateKind::Clause(ty::Clause::WellFormed(array_ty.into())), + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(array_ty.into())), Locations::Single(location), ConstraintCategory::Boring, ); @@ -2025,10 +2026,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ConstraintCategory::Cast, ); - let outlives_predicate = - tcx.mk_predicate(Binder::dummy(ty::PredicateKind::Clause( - ty::Clause::TypeOutlives(ty::OutlivesPredicate(self_ty, *region)), - ))); + let outlives_predicate = tcx.mk_predicate(Binder::dummy( + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives( + ty::OutlivesPredicate(self_ty, *region), + )), + )); self.prove_predicate( outlives_predicate, location.to_locations(), diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index b619e80e15f..902c1e40c75 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -320,6 +320,7 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::Underscore | ExprKind::While(_, _, _) | ExprKind::Yeet(_) + | ExprKind::Become(_) | ExprKind::Yield(_) => {} } } diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 49ee276af4e..fcc68010a34 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -3,7 +3,7 @@ use crate::errors; /// Ideally, this code would be in libtest but for efficiency and error messages it lives here. use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute}; use rustc_ast::ptr::P; -use rustc_ast::{self as ast, attr}; +use rustc_ast::{self as ast, attr, GenericParamKind}; use rustc_ast_pretty::pprust; use rustc_errors::Applicability; use rustc_expand::base::*; @@ -122,11 +122,7 @@ pub fn expand_test_or_bench( let ast::ItemKind::Fn(fn_) = &item.kind else { not_testable_error(cx, attr_sp, Some(&item)); return if is_stmt { - vec![Annotatable::Stmt(P(ast::Stmt { - id: ast::DUMMY_NODE_ID, - span: item.span, - kind: ast::StmtKind::Item(item), - }))] + vec![Annotatable::Stmt(P(cx.stmt_item(item.span, item)))] } else { vec![Annotatable::Item(item)] }; @@ -138,7 +134,11 @@ pub fn expand_test_or_bench( if (!is_bench && !has_test_signature(cx, &item)) || (is_bench && !has_bench_signature(cx, &item)) { - return vec![Annotatable::Item(item)]; + return if is_stmt { + vec![Annotatable::Stmt(P(cx.stmt_item(item.span, item)))] + } else { + vec![Annotatable::Item(item)] + }; } let sp = cx.with_def_site_ctxt(item.span); @@ -550,24 +550,21 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { return false; } - match (has_output, has_should_panic_attr) { - (true, true) => { - sd.span_err(i.span, "functions using `#[should_panic]` must return `()`"); - false - } - (true, false) => { - if !generics.params.is_empty() { - sd.span_err( - i.span, - "functions used as tests must have signature fn() -> ()", - ); - false - } else { - true - } - } - (false, _) => true, + if has_should_panic_attr && has_output { + sd.span_err(i.span, "functions using `#[should_panic]` must return `()`"); + return false; + } + + if generics.params.iter().any(|param| !matches!(param.kind, GenericParamKind::Lifetime)) + { + sd.span_err( + i.span, + "functions used as tests can not have any non-lifetime generic parameters", + ); + return false; } + + true } _ => { // should be unreachable because `is_test_fn_item` should catch all non-fn items diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 5abb4644e1b..ce10780f9de 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -421,7 +421,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { target, fn_span, unwind: _, - from_hir_call: _, + call_source: _, } => { fx.tcx.prof.generic_activity("codegen call").run(|| { crate::abi::codegen_terminator_call( diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs index f751d8c179d..13568b198db 100644 --- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs +++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs @@ -22,8 +22,8 @@ pub(crate) fn maybe_codegen<'tcx>( match bin_op { BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => None, - BinOp::Add | BinOp::Sub => None, - BinOp::Mul => { + BinOp::Add | BinOp::AddUnchecked | BinOp::Sub | BinOp::SubUnchecked => None, + BinOp::Mul | BinOp::MulUnchecked => { let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)]; let ret_val = fx.lib_call( "__multi3", @@ -69,7 +69,7 @@ pub(crate) fn maybe_codegen<'tcx>( } } BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => None, - BinOp::Shl | BinOp::Shr => None, + BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => None, } } @@ -131,9 +131,10 @@ pub(crate) fn maybe_codegen_checked<'tcx>( fx.lib_call(name, param_types, vec![], &args); Some(out_place.to_cvalue(fx)) } + BinOp::AddUnchecked | BinOp::SubUnchecked | BinOp::MulUnchecked => unreachable!(), BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"), BinOp::Div | BinOp::Rem => unreachable!(), BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => unreachable!(), - BinOp::Shl | BinOp::Shr => unreachable!(), + BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => unreachable!(), } } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 1e83c30bd67..5862f18299e 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -472,25 +472,11 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, CValue::by_val(align, usize_layout)); } - sym::unchecked_add - | sym::unchecked_sub - | sym::unchecked_mul - | sym::exact_div - | sym::unchecked_shl - | sym::unchecked_shr => { + sym::exact_div => { intrinsic_args!(fx, args => (x, y); intrinsic); - // FIXME trap on overflow - let bin_op = match intrinsic { - sym::unchecked_add => BinOp::Add, - sym::unchecked_sub => BinOp::Sub, - sym::unchecked_mul => BinOp::Mul, - sym::exact_div => BinOp::Div, - sym::unchecked_shl => BinOp::Shl, - sym::unchecked_shr => BinOp::Shr, - _ => unreachable!(), - }; - let res = crate::num::codegen_int_binop(fx, bin_op, x, y); + // FIXME trap on inexact + let res = crate::num::codegen_int_binop(fx, BinOp::Div, x, y); ret.write_cvalue(fx, res); } sym::saturating_add | sym::saturating_sub => { diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs index ba53e01c7a2..ac1a6cce096 100644 --- a/compiler/rustc_codegen_cranelift/src/num.rs +++ b/compiler/rustc_codegen_cranelift/src/num.rs @@ -128,10 +128,11 @@ pub(crate) fn codegen_int_binop<'tcx>( let rhs = in_rhs.load_scalar(fx); let b = fx.bcx.ins(); + // FIXME trap on overflow for the Unchecked versions let val = match bin_op { - BinOp::Add => b.iadd(lhs, rhs), - BinOp::Sub => b.isub(lhs, rhs), - BinOp::Mul => b.imul(lhs, rhs), + BinOp::Add | BinOp::AddUnchecked => b.iadd(lhs, rhs), + BinOp::Sub | BinOp::SubUnchecked => b.isub(lhs, rhs), + BinOp::Mul | BinOp::MulUnchecked => b.imul(lhs, rhs), BinOp::Div => { if signed { b.sdiv(lhs, rhs) @@ -149,16 +150,19 @@ pub(crate) fn codegen_int_binop<'tcx>( BinOp::BitXor => b.bxor(lhs, rhs), BinOp::BitAnd => b.band(lhs, rhs), BinOp::BitOr => b.bor(lhs, rhs), - BinOp::Shl => b.ishl(lhs, rhs), - BinOp::Shr => { + BinOp::Shl | BinOp::ShlUnchecked => b.ishl(lhs, rhs), + BinOp::Shr | BinOp::ShrUnchecked => { if signed { b.sshr(lhs, rhs) } else { b.ushr(lhs, rhs) } } + BinOp::Offset => unreachable!("Offset is not an integer operation"), // Compare binops handles by `codegen_binop`. - _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs.layout().ty, in_rhs.layout().ty), + BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge => { + unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs.layout().ty, in_rhs.layout().ty); + } }; CValue::by_val(val, in_lhs.layout()) diff --git a/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml b/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml index 42fb35e738f..556c6444833 100644 --- a/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml +++ b/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml @@ -20,9 +20,9 @@ jobs: matrix: libgccjit_version: - { gcc: "libgccjit.so", artifacts_branch: "master" } - commands: [ - "--test-successful-rustc --nb-parts 2 --current-part 0", - "--test-successful-rustc --nb-parts 2 --current-part 1", + cargo_runner: [ + "sde -future -rtm_mode full --", + "", ] steps: @@ -36,6 +36,20 @@ jobs: - name: Install packages run: sudo apt-get install ninja-build ripgrep + - name: Install Intel Software Development Emulator + if: ${{ matrix.cargo_runner }} + run: | + mkdir intel-sde + cd intel-sde + dir=sde-external-9.14.0-2022-10-25-lin + file=$dir.tar.xz + wget https://downloadmirror.intel.com/751535/$file + tar xvf $file + sudo mkdir /usr/share/intel-sde + sudo cp -r $dir/* /usr/share/intel-sde + sudo ln -s /usr/share/intel-sde/sde /usr/bin/sde + sudo ln -s /usr/share/intel-sde/sde64 /usr/bin/sde64 + - name: Download artifact uses: dawidd6/action-download-artifact@v2 with: @@ -91,6 +105,10 @@ jobs: ./prepare_build.sh ./build.sh --release --release-sysroot cargo test + + - name: Clean + if: ${{ !matrix.cargo_runner }} + run: | ./clean_all.sh - name: Prepare dependencies @@ -107,10 +125,18 @@ jobs: args: --release - name: Run tests + if: ${{ !matrix.cargo_runner }} run: | ./test.sh --release --clean --release-sysroot --build-sysroot --mini-tests --std-tests --test-libcore - name: Run stdarch tests + if: ${{ !matrix.cargo_runner }} run: | cd build_sysroot/sysroot_src/library/stdarch/ CHANNEL=release TARGET=x86_64-unknown-linux-gnu ../../../../cargo.sh test + + - name: Run stdarch tests + if: ${{ matrix.cargo_runner }} + run: | + cd build_sysroot/sysroot_src/library/stdarch/ + STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu ../../../../cargo.sh test -- --skip rtm --skip tbm --skip sse4a diff --git a/compiler/rustc_codegen_gcc/.gitignore b/compiler/rustc_codegen_gcc/.gitignore index 12ed5667563..c5ed7de200c 100644 --- a/compiler/rustc_codegen_gcc/.gitignore +++ b/compiler/rustc_codegen_gcc/.gitignore @@ -23,3 +23,5 @@ benchmarks tools/llvm-project tools/llvmint tools/llvmint-2 +# The `llvm` folder is generated by the `tools/generate_intrinsics.py` script to update intrinsics. +llvm diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock index 0f2e152f8ce..1c8754bf675 100644 --- a/compiler/rustc_codegen_gcc/Cargo.lock +++ b/compiler/rustc_codegen_gcc/Cargo.lock @@ -35,7 +35,7 @@ dependencies = [ [[package]] name = "gccjit" version = "1.0.0" -source = "git+https://github.com/antoyo/gccjit.rs#fe242b7eb26980e6c78859d51c8d4cc1e43381a3" +source = "git+https://github.com/antoyo/gccjit.rs#d6e52626cfc6f487094a5d5ac66302baf3439984" dependencies = [ "gccjit_sys", ] @@ -43,7 +43,7 @@ dependencies = [ [[package]] name = "gccjit_sys" version = "0.0.1" -source = "git+https://github.com/antoyo/gccjit.rs#fe242b7eb26980e6c78859d51c8d4cc1e43381a3" +source = "git+https://github.com/antoyo/gccjit.rs#d6e52626cfc6f487094a5d5ac66302baf3439984" dependencies = [ "libc", ] diff --git a/compiler/rustc_codegen_gcc/Readme.md b/compiler/rustc_codegen_gcc/Readme.md index bb741943892..a93637d9038 100644 --- a/compiler/rustc_codegen_gcc/Readme.md +++ b/compiler/rustc_codegen_gcc/Readme.md @@ -193,7 +193,7 @@ Using git-subtree with `rustc` requires a patched git to make it work. The PR that is needed is [here](https://github.com/gitgitgadget/git/pull/493). Use the following instructions to install it: -``` +```bash git clone git@github.com:tqc/git.git cd git git checkout tqc/subtree @@ -204,6 +204,21 @@ make cp git-subtree ~/bin ``` +Then, do a sync with this command: + +```bash +PATH="$HOME/bin:$PATH" ~/bin/git-subtree push -P compiler/rustc_codegen_gcc/ ../rustc_codegen_gcc/ sync_branch_name +cd ../rustc_codegen_gcc +git checkout master +git pull +git checkout sync_branch_name +git merge master +``` + +TODO: write a script that does the above. + +https://rust-lang.zulipchat.com/#narrow/stream/301329-t-devtools/topic/subtree.20madness/near/258877725 + ### How to use [mem-trace](https://github.com/antoyo/mem-trace) `rustc` needs to be built without `jemalloc` so that `mem-trace` can overload `malloc` since `jemalloc` is linked statically, so a `LD_PRELOAD`-ed library won't a chance to intercept the calls to `malloc`. diff --git a/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml b/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml index cfadf47cc3f..a84f86a8218 100644 --- a/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml +++ b/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml @@ -9,6 +9,7 @@ compiler_builtins = "0.1" alloc = { path = "./sysroot_src/library/alloc" } std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] } test = { path = "./sysroot_src/library/test" } +proc_macro = { path = "./sysroot_src/library/proc_macro" } [patch.crates-io] rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-core" } diff --git a/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh b/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh index 56768bbf1d0..71b3876bac2 100755 --- a/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh +++ b/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh @@ -29,10 +29,10 @@ git config user.name || git config user.name "None" git commit -m "Initial commit" -q for file in $(ls ../../patches/ | grep -v patcha); do -echo "[GIT] apply" $file -git apply ../../patches/$file -git add -A -git commit --no-gpg-sign -m "Patch $file" + echo "[GIT] apply" $file + git apply ../../patches/$file + git add -A + git commit --no-gpg-sign -m "Patch $file" done popd diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs index c27b610f2ab..0cd7e6047c2 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs @@ -451,6 +451,9 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) { drop_in_place(to_drop); } +#[lang = "unpin"] +pub auto trait Unpin {} + #[lang = "deref"] pub trait Deref { type Target: ?Sized; @@ -488,10 +491,23 @@ pub struct Box<T: ?Sized, A: Allocator = Global>(Unique<T>, A); impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {} +impl<T> Box<T> { + pub fn new(val: T) -> Box<T> { + unsafe { + let size = intrinsics::size_of::<T>(); + let ptr = libc::malloc(size); + intrinsics::copy(&val as *const T as *const u8, ptr, size); + Box(Unique { pointer: NonNull(ptr as *const T), _marker: PhantomData }, Global) + } + } +} + impl<T: ?Sized, A: Allocator> Drop for Box<T, A> { fn drop(&mut self) { - // inner value is dropped by compiler - libc::free(self.pointer.0 as *mut u8); + // inner value is dropped by compiler. + unsafe { + libc::free(self.0.pointer.0 as *mut u8); + } } } diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs index cff26077740..b93d6859706 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs @@ -168,6 +168,9 @@ fn main() { world as Box<dyn SomeTrait>; assert_eq!(intrinsics::bitreverse(0b10101000u8), 0b00010101u8); + assert_eq!(intrinsics::bitreverse(0xddccu16), 0x33bbu16); + assert_eq!(intrinsics::bitreverse(0xffee_ddccu32), 0x33bb77ffu32); + assert_eq!(intrinsics::bitreverse(0x1234_5678_ffee_ddccu64), 0x33bb77ff1e6a2c48u64); assert_eq!(intrinsics::bswap(0xabu8), 0xabu8); assert_eq!(intrinsics::bswap(0xddccu16), 0xccddu16); diff --git a/compiler/rustc_codegen_gcc/example/std_example.rs b/compiler/rustc_codegen_gcc/example/std_example.rs index 5c171c49fd1..18f2ddcde12 100644 --- a/compiler/rustc_codegen_gcc/example/std_example.rs +++ b/compiler/rustc_codegen_gcc/example/std_example.rs @@ -58,6 +58,7 @@ fn main() { assert_eq!(0b0000000000000000000000000010000010000000000000000000000000000000_0000000000100000000000000000000000001000000000000100000000000000u128.leading_zeros(), 26); assert_eq!(0b0000000000000000000000000010000000000000000000000000000000000000_0000000000000000000000000000000000001000000000000000000010000000u128.trailing_zeros(), 7); + assert_eq!(0x1234_5678_ffee_ddcc_1234_5678_ffee_ddccu128.reverse_bits(), 0x33bb77ff1e6a2c4833bb77ff1e6a2c48u128); let _d = 0i128.checked_div(2i128); let _d = 0u128.checked_div(2u128); diff --git a/compiler/rustc_codegen_gcc/failing-ui-tests.txt b/compiler/rustc_codegen_gcc/failing-ui-tests.txt index 8539e27ea6a..801464daae9 100644 --- a/compiler/rustc_codegen_gcc/failing-ui-tests.txt +++ b/compiler/rustc_codegen_gcc/failing-ui-tests.txt @@ -54,8 +54,8 @@ tests/ui/issues/issue-40883.rs tests/ui/issues/issue-43853.rs tests/ui/issues/issue-47364.rs tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs -tests/ui/rfc-2091-track-caller/std-panic-locations.rs -tests/ui/rfcs/rfc1857-drop-order.rs +tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs +tests/ui/rfcs/rfc-1857-stabilize-drop-order/drop-order.rs tests/ui/simd/issue-17170.rs tests/ui/simd/issue-39720.rs tests/ui/simd/issue-89193.rs @@ -66,3 +66,5 @@ tests/ui/generator/panic-safe.rs tests/ui/issues/issue-14875.rs tests/ui/issues/issue-29948.rs tests/ui/panic-while-printing.rs +tests/ui/enum-discriminant/get_discr.rs +tests/ui/panics/nested_panic_caught.rs diff --git a/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch b/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch deleted file mode 100644 index ee5ba449fb8..00000000000 --- a/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch +++ /dev/null @@ -1,49 +0,0 @@ -From dd82e95c9de212524e14fc60155de1ae40156dfc Mon Sep 17 00:00:00 2001 -From: bjorn3 <bjorn3@users.noreply.github.com> -Date: Sun, 24 Nov 2019 15:34:06 +0100 -Subject: [PATCH] [core] Ignore failing tests - ---- - library/core/tests/iter.rs | 4 ++++ - library/core/tests/num/bignum.rs | 10 ++++++++++ - library/core/tests/num/mod.rs | 5 +++-- - library/core/tests/time.rs | 1 + - 4 files changed, 18 insertions(+), 2 deletions(-) - -diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs -index 4bc44e9..8e3c7a4 100644 ---- a/library/core/tests/array.rs -+++ b/library/core/tests/array.rs -@@ -242,6 +242,7 @@ fn iterator_drops() { - assert_eq!(i.get(), 5); - } - -+/* - // This test does not work on targets without panic=unwind support. - // To work around this problem, test is marked is should_panic, so it will - // be automagically skipped on unsuitable targets, such as -@@ -283,6 +284,7 @@ fn array_default_impl_avoids_leaks_on_panic() { - assert_eq!(COUNTER.load(Relaxed), 0); - panic!("test succeeded") - } -+*/ - - #[test] - fn empty_array_is_always_default() { -@@ -304,6 +304,7 @@ fn array_map() { - assert_eq!(b, [1, 2, 3]); - } - -+/* - // See note on above test for why `should_panic` is used. - #[test] - #[should_panic(expected = "test succeeded")] -@@ -332,6 +333,7 @@ fn array_map_drop_safety() { - assert_eq!(DROPPED.load(Ordering::SeqCst), num_to_create); - panic!("test succeeded") - } -+*/ - - #[test] - fn cell_allows_array_cycle() { --- 2.21.0 (Apple Git-122) diff --git a/compiler/rustc_codegen_gcc/rust-toolchain b/compiler/rustc_codegen_gcc/rust-toolchain index 933ecd45baa..ebb04d0069c 100644 --- a/compiler/rustc_codegen_gcc/rust-toolchain +++ b/compiler/rustc_codegen_gcc/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-03-02" +channel = "nightly-2023-06-19" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 250aa79f8d6..4c3b7f5036c 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -518,7 +518,6 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { OperandValue::Immediate(op.tmp_var.to_rvalue()).store(self, place); } } - } } diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs index db841b1b524..eb0cce19b85 100644 --- a/compiler/rustc_codegen_gcc/src/attributes.rs +++ b/compiler/rustc_codegen_gcc/src/attributes.rs @@ -2,9 +2,13 @@ use gccjit::FnAttribute; use gccjit::Function; use rustc_attr::InstructionSetAttr; +#[cfg(feature="master")] +use rustc_attr::InlineAttr; use rustc_codegen_ssa::target_features::tied_target_features; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty; +#[cfg(feature="master")] +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_session::Session; use rustc_span::symbol::sym; use smallvec::{smallvec, SmallVec}; @@ -67,6 +71,24 @@ fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> { } } +/// Get GCC attribute for the provided inline heuristic. +#[cfg(feature="master")] +#[inline] +fn inline_attr<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, inline: InlineAttr) -> Option<FnAttribute<'gcc>> { + match inline { + InlineAttr::Hint => Some(FnAttribute::Inline), + InlineAttr::Always => Some(FnAttribute::AlwaysInline), + InlineAttr::Never => { + if cx.sess().target.arch != "amdgpu" { + Some(FnAttribute::NoInline) + } else { + None + } + } + InlineAttr::None => None, + } +} + /// Composite function which sets GCC attributes for function depending on its AST (`#[attribute]`) /// attributes. pub fn from_fn_attrs<'gcc, 'tcx>( @@ -77,6 +99,23 @@ pub fn from_fn_attrs<'gcc, 'tcx>( ) { let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id()); + #[cfg(feature="master")] + { + let inline = + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { + InlineAttr::Never + } + else if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) { + InlineAttr::Hint + } + else { + codegen_fn_attrs.inline + }; + if let Some(attr) = inline_attr(cx, inline) { + func.add_attribute(attr); + } + } + let function_features = codegen_fn_attrs.target_features.iter().map(|features| features.as_str()).collect::<Vec<&str>>(); diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index f9ea0f00456..43d0aafbd50 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -181,6 +181,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { }) .collect(); + debug_assert_eq!(casted_args.len(), args.len()); + Cow::Owned(casted_args) } @@ -207,7 +209,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let func_name = format!("{:?}", func_ptr); - let casted_args: Vec<_> = param_types + let mut casted_args: Vec<_> = param_types .into_iter() .zip(args.iter()) .enumerate() @@ -237,6 +239,11 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { }) .collect(); + // NOTE: to take into account variadic functions. + for i in casted_args.len()..args.len() { + casted_args.push(args[i]); + } + Cow::Owned(casted_args) } @@ -280,8 +287,17 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } } - fn function_ptr_call(&mut self, func_ptr: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> { - let gcc_func = func_ptr.get_type().dyncast_function_ptr_type().expect("function ptr"); + fn function_ptr_call(&mut self, typ: Type<'gcc>, mut func_ptr: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> { + let gcc_func = + match func_ptr.get_type().dyncast_function_ptr_type() { + Some(func) => func, + None => { + // NOTE: due to opaque pointers now being used, we need to cast here. + let new_func_type = typ.dyncast_function_ptr_type().expect("function ptr"); + func_ptr = self.context.new_cast(None, func_ptr, typ); + new_func_type + }, + }; let func_name = format!("{:?}", func_ptr); let previous_arg_count = args.len(); let orig_args = args; @@ -424,16 +440,17 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.llbb().end_with_void_return(None) } - fn ret(&mut self, value: RValue<'gcc>) { - let value = - if self.structs_as_pointer.borrow().contains(&value) { - // NOTE: hack to workaround a limitation of the rustc API: see comment on - // CodegenCx.structs_as_pointer - value.dereference(None).to_rvalue() - } - else { - value - }; + fn ret(&mut self, mut value: RValue<'gcc>) { + if self.structs_as_pointer.borrow().contains(&value) { + // NOTE: hack to workaround a limitation of the rustc API: see comment on + // CodegenCx.structs_as_pointer + value = value.dereference(None).to_rvalue(); + } + let expected_return_type = self.current_func().get_return_type(); + if !expected_return_type.is_compatible_with(value.get_type()) { + // NOTE: due to opaque pointers now being used, we need to cast here. + value = self.context.new_cast(None, value, expected_return_type); + } self.llbb().end_with_return(None, value); } @@ -719,17 +736,25 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { unimplemented!(); } - fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, _align: Align) -> RValue<'gcc> { + fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { let block = self.llbb(); let function = block.get_function(); // NOTE: instead of returning the dereference here, we have to assign it to a variable in // the current basic block. Otherwise, it could be used in another basic block, causing a // dereference after a drop, for instance. - // TODO(antoyo): handle align of the load instruction. - let ptr = self.context.new_cast(None, ptr, pointee_ty.make_pointer()); + // FIXME(antoyo): this check that we don't call get_aligned() a second time on a type. + // Ideally, we shouldn't need to do this check. + let aligned_type = + if pointee_ty == self.cx.u128_type || pointee_ty == self.cx.i128_type { + pointee_ty + } + else { + pointee_ty.get_aligned(align.bytes()) + }; + let ptr = self.context.new_cast(None, ptr, aligned_type.make_pointer()); let deref = ptr.dereference(None).to_rvalue(); unsafe { RETURN_VALUE_COUNT += 1 }; - let loaded_value = function.new_local(None, pointee_ty, &format!("loadedValue{}", unsafe { RETURN_VALUE_COUNT })); + let loaded_value = function.new_local(None, aligned_type, &format!("loadedValue{}", unsafe { RETURN_VALUE_COUNT })); block.add_assignment(None, loaded_value, deref); loaded_value.to_rvalue() } @@ -909,7 +934,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.context.new_bitcast(None, result, ptr_type) } - fn inbounds_gep(&mut self, _typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> { + fn inbounds_gep(&mut self, typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> { + // NOTE: due to opaque pointers now being used, we need to cast here. + let ptr = self.context.new_cast(None, ptr, typ.make_pointer()); // NOTE: array indexing is always considered in bounds in GCC (TODO(antoyo): to be verified). let mut indices = indices.into_iter(); let index = indices.next().expect("first index in inbounds_gep"); @@ -938,6 +965,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { element.get_address(None) } else if let Some(struct_type) = value_type.is_struct() { + // NOTE: due to opaque pointers now being used, we need to bitcast here. + let ptr = self.bitcast_if_needed(ptr, value_type.make_pointer()); ptr.dereference_field(None, struct_type.get_field(idx as i32)).get_address(None) } else { @@ -1356,7 +1385,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn call( &mut self, - _typ: Type<'gcc>, + typ: Type<'gcc>, _fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, @@ -1370,7 +1399,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } else { // If it's a not function that was defined, it's a function pointer. - self.function_ptr_call(func, args, funclet) + self.function_ptr_call(typ, func, args, funclet) }; if let Some(_fn_abi) = fn_abi { // TODO(bjorn3): Apply function attributes @@ -1843,7 +1872,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { #[cfg(feature="master")] let (cond, element_type) = { - let then_val_vector_type = then_val.get_type().dyncast_vector().expect("vector type"); + // TODO(antoyo): dyncast_vector should not require a call to unqualified. + let then_val_vector_type = then_val.get_type().unqualified().dyncast_vector().expect("vector type"); let then_val_element_type = then_val_vector_type.get_element_type(); let then_val_element_size = then_val_element_type.get_size(); diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index 33e3b0baa92..d8a1fd315c0 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -1,5 +1,5 @@ #[cfg(feature = "master")] -use gccjit::FnAttribute; +use gccjit::{FnAttribute, VarAttribute, Visibility}; use gccjit::{Function, GlobalKind, LValue, RValue, ToRValue}; use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, DerivedTypeMethods, StaticMethods}; use rustc_middle::span_bug; @@ -234,7 +234,8 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { ); if !self.tcx.is_reachable_non_generic(def_id) { - // TODO(antoyo): set visibility. + #[cfg(feature = "master")] + global.add_attribute(VarAttribute::Visibility(Visibility::Hidden)); } global diff --git a/compiler/rustc_codegen_gcc/src/declare.rs b/compiler/rustc_codegen_gcc/src/declare.rs index 4748e7e4be2..493626c3cf5 100644 --- a/compiler/rustc_codegen_gcc/src/declare.rs +++ b/compiler/rustc_codegen_gcc/src/declare.rs @@ -132,7 +132,7 @@ fn declare_raw_fn<'gcc>(cx: &CodegenCx<'gcc, '_>, name: &str, _callconv: () /*ll pub fn mangle_name(name: &str) -> String { name.replace(|char: char| { if !char.is_alphanumeric() && char != '_' { - debug_assert!("$.".contains(char), "Unsupported char in function name: {}", char); + debug_assert!("$.*".contains(char), "Unsupported char in function name {}: {}", name, char); true } else { diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs b/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs index 8a4559355ea..438eab78943 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs @@ -2967,10 +2967,6 @@ match name { "llvm.nvvm.clz.ll" => "__nvvm_clz_ll", "llvm.nvvm.cos.approx.f" => "__nvvm_cos_approx_f", "llvm.nvvm.cos.approx.ftz.f" => "__nvvm_cos_approx_ftz_f", - "llvm.nvvm.cp.async.ca.shared.global.16" => "__nvvm_cp_async_ca_shared_global_16", - "llvm.nvvm.cp.async.ca.shared.global.4" => "__nvvm_cp_async_ca_shared_global_4", - "llvm.nvvm.cp.async.ca.shared.global.8" => "__nvvm_cp_async_ca_shared_global_8", - "llvm.nvvm.cp.async.cg.shared.global.16" => "__nvvm_cp_async_cg_shared_global_16", "llvm.nvvm.cp.async.commit.group" => "__nvvm_cp_async_commit_group", "llvm.nvvm.cp.async.mbarrier.arrive" => "__nvvm_cp_async_mbarrier_arrive", "llvm.nvvm.cp.async.mbarrier.arrive.noinc" => "__nvvm_cp_async_mbarrier_arrive_noinc", @@ -3086,18 +3082,8 @@ match name { "llvm.nvvm.fma.rn.f16" => "__nvvm_fma_rn_f16", "llvm.nvvm.fma.rn.f16x2" => "__nvvm_fma_rn_f16x2", "llvm.nvvm.fma.rn.ftz.f" => "__nvvm_fma_rn_ftz_f", - "llvm.nvvm.fma.rn.ftz.f16" => "__nvvm_fma_rn_ftz_f16", - "llvm.nvvm.fma.rn.ftz.f16x2" => "__nvvm_fma_rn_ftz_f16x2", - "llvm.nvvm.fma.rn.ftz.relu.f16" => "__nvvm_fma_rn_ftz_relu_f16", - "llvm.nvvm.fma.rn.ftz.relu.f16x2" => "__nvvm_fma_rn_ftz_relu_f16x2", - "llvm.nvvm.fma.rn.ftz.sat.f16" => "__nvvm_fma_rn_ftz_sat_f16", - "llvm.nvvm.fma.rn.ftz.sat.f16x2" => "__nvvm_fma_rn_ftz_sat_f16x2", "llvm.nvvm.fma.rn.relu.bf16" => "__nvvm_fma_rn_relu_bf16", "llvm.nvvm.fma.rn.relu.bf16x2" => "__nvvm_fma_rn_relu_bf16x2", - "llvm.nvvm.fma.rn.relu.f16" => "__nvvm_fma_rn_relu_f16", - "llvm.nvvm.fma.rn.relu.f16x2" => "__nvvm_fma_rn_relu_f16x2", - "llvm.nvvm.fma.rn.sat.f16" => "__nvvm_fma_rn_sat_f16", - "llvm.nvvm.fma.rn.sat.f16x2" => "__nvvm_fma_rn_sat_f16x2", "llvm.nvvm.fma.rp.d" => "__nvvm_fma_rp_d", "llvm.nvvm.fma.rp.f" => "__nvvm_fma_rp_f", "llvm.nvvm.fma.rp.ftz.f" => "__nvvm_fma_rp_ftz_f", @@ -3111,32 +3097,18 @@ match name { "llvm.nvvm.fmax.f16" => "__nvvm_fmax_f16", "llvm.nvvm.fmax.f16x2" => "__nvvm_fmax_f16x2", "llvm.nvvm.fmax.ftz.f" => "__nvvm_fmax_ftz_f", - "llvm.nvvm.fmax.ftz.f16" => "__nvvm_fmax_ftz_f16", - "llvm.nvvm.fmax.ftz.f16x2" => "__nvvm_fmax_ftz_f16x2", "llvm.nvvm.fmax.ftz.nan.f" => "__nvvm_fmax_ftz_nan_f", - "llvm.nvvm.fmax.ftz.nan.f16" => "__nvvm_fmax_ftz_nan_f16", - "llvm.nvvm.fmax.ftz.nan.f16x2" => "__nvvm_fmax_ftz_nan_f16x2", "llvm.nvvm.fmax.ftz.nan.xorsign.abs.f" => "__nvvm_fmax_ftz_nan_xorsign_abs_f", - "llvm.nvvm.fmax.ftz.nan.xorsign.abs.f16" => "__nvvm_fmax_ftz_nan_xorsign_abs_f16", - "llvm.nvvm.fmax.ftz.nan.xorsign.abs.f16x2" => "__nvvm_fmax_ftz_nan_xorsign_abs_f16x2", "llvm.nvvm.fmax.ftz.xorsign.abs.f" => "__nvvm_fmax_ftz_xorsign_abs_f", - "llvm.nvvm.fmax.ftz.xorsign.abs.f16" => "__nvvm_fmax_ftz_xorsign_abs_f16", - "llvm.nvvm.fmax.ftz.xorsign.abs.f16x2" => "__nvvm_fmax_ftz_xorsign_abs_f16x2", "llvm.nvvm.fmax.nan.bf16" => "__nvvm_fmax_nan_bf16", "llvm.nvvm.fmax.nan.bf16x2" => "__nvvm_fmax_nan_bf16x2", "llvm.nvvm.fmax.nan.f" => "__nvvm_fmax_nan_f", - "llvm.nvvm.fmax.nan.f16" => "__nvvm_fmax_nan_f16", - "llvm.nvvm.fmax.nan.f16x2" => "__nvvm_fmax_nan_f16x2", "llvm.nvvm.fmax.nan.xorsign.abs.bf16" => "__nvvm_fmax_nan_xorsign_abs_bf16", "llvm.nvvm.fmax.nan.xorsign.abs.bf16x2" => "__nvvm_fmax_nan_xorsign_abs_bf16x2", "llvm.nvvm.fmax.nan.xorsign.abs.f" => "__nvvm_fmax_nan_xorsign_abs_f", - "llvm.nvvm.fmax.nan.xorsign.abs.f16" => "__nvvm_fmax_nan_xorsign_abs_f16", - "llvm.nvvm.fmax.nan.xorsign.abs.f16x2" => "__nvvm_fmax_nan_xorsign_abs_f16x2", "llvm.nvvm.fmax.xorsign.abs.bf16" => "__nvvm_fmax_xorsign_abs_bf16", "llvm.nvvm.fmax.xorsign.abs.bf16x2" => "__nvvm_fmax_xorsign_abs_bf16x2", "llvm.nvvm.fmax.xorsign.abs.f" => "__nvvm_fmax_xorsign_abs_f", - "llvm.nvvm.fmax.xorsign.abs.f16" => "__nvvm_fmax_xorsign_abs_f16", - "llvm.nvvm.fmax.xorsign.abs.f16x2" => "__nvvm_fmax_xorsign_abs_f16x2", "llvm.nvvm.fmin.bf16" => "__nvvm_fmin_bf16", "llvm.nvvm.fmin.bf16x2" => "__nvvm_fmin_bf16x2", "llvm.nvvm.fmin.d" => "__nvvm_fmin_d", @@ -3144,32 +3116,18 @@ match name { "llvm.nvvm.fmin.f16" => "__nvvm_fmin_f16", "llvm.nvvm.fmin.f16x2" => "__nvvm_fmin_f16x2", "llvm.nvvm.fmin.ftz.f" => "__nvvm_fmin_ftz_f", - "llvm.nvvm.fmin.ftz.f16" => "__nvvm_fmin_ftz_f16", - "llvm.nvvm.fmin.ftz.f16x2" => "__nvvm_fmin_ftz_f16x2", "llvm.nvvm.fmin.ftz.nan.f" => "__nvvm_fmin_ftz_nan_f", - "llvm.nvvm.fmin.ftz.nan.f16" => "__nvvm_fmin_ftz_nan_f16", - "llvm.nvvm.fmin.ftz.nan.f16x2" => "__nvvm_fmin_ftz_nan_f16x2", "llvm.nvvm.fmin.ftz.nan.xorsign.abs.f" => "__nvvm_fmin_ftz_nan_xorsign_abs_f", - "llvm.nvvm.fmin.ftz.nan.xorsign.abs.f16" => "__nvvm_fmin_ftz_nan_xorsign_abs_f16", - "llvm.nvvm.fmin.ftz.nan.xorsign.abs.f16x2" => "__nvvm_fmin_ftz_nan_xorsign_abs_f16x2", "llvm.nvvm.fmin.ftz.xorsign.abs.f" => "__nvvm_fmin_ftz_xorsign_abs_f", - "llvm.nvvm.fmin.ftz.xorsign.abs.f16" => "__nvvm_fmin_ftz_xorsign_abs_f16", - "llvm.nvvm.fmin.ftz.xorsign.abs.f16x2" => "__nvvm_fmin_ftz_xorsign_abs_f16x2", "llvm.nvvm.fmin.nan.bf16" => "__nvvm_fmin_nan_bf16", "llvm.nvvm.fmin.nan.bf16x2" => "__nvvm_fmin_nan_bf16x2", "llvm.nvvm.fmin.nan.f" => "__nvvm_fmin_nan_f", - "llvm.nvvm.fmin.nan.f16" => "__nvvm_fmin_nan_f16", - "llvm.nvvm.fmin.nan.f16x2" => "__nvvm_fmin_nan_f16x2", "llvm.nvvm.fmin.nan.xorsign.abs.bf16" => "__nvvm_fmin_nan_xorsign_abs_bf16", "llvm.nvvm.fmin.nan.xorsign.abs.bf16x2" => "__nvvm_fmin_nan_xorsign_abs_bf16x2", "llvm.nvvm.fmin.nan.xorsign.abs.f" => "__nvvm_fmin_nan_xorsign_abs_f", - "llvm.nvvm.fmin.nan.xorsign.abs.f16" => "__nvvm_fmin_nan_xorsign_abs_f16", - "llvm.nvvm.fmin.nan.xorsign.abs.f16x2" => "__nvvm_fmin_nan_xorsign_abs_f16x2", "llvm.nvvm.fmin.xorsign.abs.bf16" => "__nvvm_fmin_xorsign_abs_bf16", "llvm.nvvm.fmin.xorsign.abs.bf16x2" => "__nvvm_fmin_xorsign_abs_bf16x2", "llvm.nvvm.fmin.xorsign.abs.f" => "__nvvm_fmin_xorsign_abs_f", - "llvm.nvvm.fmin.xorsign.abs.f16" => "__nvvm_fmin_xorsign_abs_f16", - "llvm.nvvm.fmin.xorsign.abs.f16x2" => "__nvvm_fmin_xorsign_abs_f16x2", "llvm.nvvm.fns" => "__nvvm_fns", "llvm.nvvm.h2f" => "__nvvm_h2f", "llvm.nvvm.i2d.rm" => "__nvvm_i2d_rm", @@ -7895,6 +7853,10 @@ match name { "llvm.x86.subborrow.u64" => "__builtin_ia32_subborrow_u64", "llvm.x86.tbm.bextri.u32" => "__builtin_ia32_bextri_u32", "llvm.x86.tbm.bextri.u64" => "__builtin_ia32_bextri_u64", + "llvm.x86.tcmmimfp16ps" => "__builtin_ia32_tcmmimfp16ps", + "llvm.x86.tcmmimfp16ps.internal" => "__builtin_ia32_tcmmimfp16ps_internal", + "llvm.x86.tcmmrlfp16ps" => "__builtin_ia32_tcmmrlfp16ps", + "llvm.x86.tcmmrlfp16ps.internal" => "__builtin_ia32_tcmmrlfp16ps_internal", "llvm.x86.tdpbf16ps" => "__builtin_ia32_tdpbf16ps", "llvm.x86.tdpbf16ps.internal" => "__builtin_ia32_tdpbf16ps_internal", "llvm.x86.tdpbssd" => "__builtin_ia32_tdpbssd", diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs index 0edec566be3..f28348380d7 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs @@ -313,6 +313,13 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc let new_args = args.to_vec(); args = vec![new_args[1], new_args[0], new_args[2], new_args[3], new_args[4]].into(); }, + "__builtin_ia32_vpshrdv_v8di" | "__builtin_ia32_vpshrdv_v4di" | "__builtin_ia32_vpshrdv_v2di" | + "__builtin_ia32_vpshrdv_v16si" | "__builtin_ia32_vpshrdv_v8si" | "__builtin_ia32_vpshrdv_v4si" | + "__builtin_ia32_vpshrdv_v32hi" | "__builtin_ia32_vpshrdv_v16hi" | "__builtin_ia32_vpshrdv_v8hi" => { + // The first two arguments are reversed, compared to LLVM. + let new_args = args.to_vec(); + args = vec![new_args[1], new_args[0], new_args[2]].into(); + }, _ => (), } } diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 60176874747..a31fee39918 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -551,141 +551,52 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let context = &self.cx.context; let result = match width { - 8 => { - // First step. - let left = self.and(value, context.new_rvalue_from_int(typ, 0xF0)); - let left = self.lshr(left, context.new_rvalue_from_int(typ, 4)); - let right = self.and(value, context.new_rvalue_from_int(typ, 0x0F)); - let right = self.shl(right, context.new_rvalue_from_int(typ, 4)); - let step1 = self.or(left, right); - - // Second step. - let left = self.and(step1, context.new_rvalue_from_int(typ, 0xCC)); - let left = self.lshr(left, context.new_rvalue_from_int(typ, 2)); - let right = self.and(step1, context.new_rvalue_from_int(typ, 0x33)); - let right = self.shl(right, context.new_rvalue_from_int(typ, 2)); - let step2 = self.or(left, right); - - // Third step. - let left = self.and(step2, context.new_rvalue_from_int(typ, 0xAA)); - let left = self.lshr(left, context.new_rvalue_from_int(typ, 1)); - let right = self.and(step2, context.new_rvalue_from_int(typ, 0x55)); - let right = self.shl(right, context.new_rvalue_from_int(typ, 1)); - let step3 = self.or(left, right); - - step3 - }, - 16 => { - // First step. - let left = self.and(value, context.new_rvalue_from_int(typ, 0x5555)); - let left = self.shl(left, context.new_rvalue_from_int(typ, 1)); - let right = self.and(value, context.new_rvalue_from_int(typ, 0xAAAA)); - let right = self.lshr(right, context.new_rvalue_from_int(typ, 1)); - let step1 = self.or(left, right); - - // Second step. - let left = self.and(step1, context.new_rvalue_from_int(typ, 0x3333)); - let left = self.shl(left, context.new_rvalue_from_int(typ, 2)); - let right = self.and(step1, context.new_rvalue_from_int(typ, 0xCCCC)); - let right = self.lshr(right, context.new_rvalue_from_int(typ, 2)); - let step2 = self.or(left, right); - - // Third step. - let left = self.and(step2, context.new_rvalue_from_int(typ, 0x0F0F)); - let left = self.shl(left, context.new_rvalue_from_int(typ, 4)); - let right = self.and(step2, context.new_rvalue_from_int(typ, 0xF0F0)); - let right = self.lshr(right, context.new_rvalue_from_int(typ, 4)); - let step3 = self.or(left, right); - - // Fourth step. - let left = self.and(step3, context.new_rvalue_from_int(typ, 0x00FF)); - let left = self.shl(left, context.new_rvalue_from_int(typ, 8)); - let right = self.and(step3, context.new_rvalue_from_int(typ, 0xFF00)); - let right = self.lshr(right, context.new_rvalue_from_int(typ, 8)); - let step4 = self.or(left, right); + 8 | 16 | 32 | 64 => { + let mask = ((1u128 << width) - 1) as u64; + let (m0, m1, m2) = if width > 16 { + ( + context.new_rvalue_from_long(typ, (0x5555555555555555u64 & mask) as i64), + context.new_rvalue_from_long(typ, (0x3333333333333333u64 & mask) as i64), + context.new_rvalue_from_long(typ, (0x0f0f0f0f0f0f0f0fu64 & mask) as i64), + ) + } else { + ( + context.new_rvalue_from_int(typ, (0x5555u64 & mask) as i32), + context.new_rvalue_from_int(typ, (0x3333u64 & mask) as i32), + context.new_rvalue_from_int(typ, (0x0f0fu64 & mask) as i32), + ) + }; + let one = context.new_rvalue_from_int(typ, 1); + let two = context.new_rvalue_from_int(typ, 2); + let four = context.new_rvalue_from_int(typ, 4); - step4 - }, - 32 => { - // TODO(antoyo): Refactor with other implementations. // First step. - let left = self.and(value, context.new_rvalue_from_long(typ, 0x55555555)); - let left = self.shl(left, context.new_rvalue_from_long(typ, 1)); - let right = self.and(value, context.new_rvalue_from_long(typ, 0xAAAAAAAA)); - let right = self.lshr(right, context.new_rvalue_from_long(typ, 1)); + let left = self.lshr(value, one); + let left = self.and(left, m0); + let right = self.and(value, m0); + let right = self.shl(right, one); let step1 = self.or(left, right); // Second step. - let left = self.and(step1, context.new_rvalue_from_long(typ, 0x33333333)); - let left = self.shl(left, context.new_rvalue_from_long(typ, 2)); - let right = self.and(step1, context.new_rvalue_from_long(typ, 0xCCCCCCCC)); - let right = self.lshr(right, context.new_rvalue_from_long(typ, 2)); + let left = self.lshr(step1, two); + let left = self.and(left, m1); + let right = self.and(step1, m1); + let right = self.shl(right, two); let step2 = self.or(left, right); // Third step. - let left = self.and(step2, context.new_rvalue_from_long(typ, 0x0F0F0F0F)); - let left = self.shl(left, context.new_rvalue_from_long(typ, 4)); - let right = self.and(step2, context.new_rvalue_from_long(typ, 0xF0F0F0F0)); - let right = self.lshr(right, context.new_rvalue_from_long(typ, 4)); + let left = self.lshr(step2, four); + let left = self.and(left, m2); + let right = self.and(step2, m2); + let right = self.shl(right, four); let step3 = self.or(left, right); // Fourth step. - let left = self.and(step3, context.new_rvalue_from_long(typ, 0x00FF00FF)); - let left = self.shl(left, context.new_rvalue_from_long(typ, 8)); - let right = self.and(step3, context.new_rvalue_from_long(typ, 0xFF00FF00)); - let right = self.lshr(right, context.new_rvalue_from_long(typ, 8)); - let step4 = self.or(left, right); - - // Fifth step. - let left = self.and(step4, context.new_rvalue_from_long(typ, 0x0000FFFF)); - let left = self.shl(left, context.new_rvalue_from_long(typ, 16)); - let right = self.and(step4, context.new_rvalue_from_long(typ, 0xFFFF0000)); - let right = self.lshr(right, context.new_rvalue_from_long(typ, 16)); - let step5 = self.or(left, right); - - step5 - }, - 64 => { - // First step. - let left = self.shl(value, context.new_rvalue_from_long(typ, 32)); - let right = self.lshr(value, context.new_rvalue_from_long(typ, 32)); - let step1 = self.or(left, right); - - // Second step. - let left = self.and(step1, context.new_rvalue_from_long(typ, 0x0001FFFF0001FFFF)); - let left = self.shl(left, context.new_rvalue_from_long(typ, 15)); - let right = self.and(step1, context.new_rvalue_from_long(typ, 0xFFFE0000FFFE0000u64 as i64)); // TODO(antoyo): transmute the number instead? - let right = self.lshr(right, context.new_rvalue_from_long(typ, 17)); - let step2 = self.or(left, right); - - // Third step. - let left = self.lshr(step2, context.new_rvalue_from_long(typ, 10)); - let left = self.xor(step2, left); - let temp = self.and(left, context.new_rvalue_from_long(typ, 0x003F801F003F801F)); - - let left = self.shl(temp, context.new_rvalue_from_long(typ, 10)); - let left = self.or(temp, left); - let step3 = self.xor(left, step2); - - // Fourth step. - let left = self.lshr(step3, context.new_rvalue_from_long(typ, 4)); - let left = self.xor(step3, left); - let temp = self.and(left, context.new_rvalue_from_long(typ, 0x0E0384210E038421)); - - let left = self.shl(temp, context.new_rvalue_from_long(typ, 4)); - let left = self.or(temp, left); - let step4 = self.xor(left, step3); - - // Fifth step. - let left = self.lshr(step4, context.new_rvalue_from_long(typ, 2)); - let left = self.xor(step4, left); - let temp = self.and(left, context.new_rvalue_from_long(typ, 0x2248884222488842)); - - let left = self.shl(temp, context.new_rvalue_from_long(typ, 2)); - let left = self.or(temp, left); - let step5 = self.xor(left, step4); - - step5 + if width == 8 { + step3 + } else { + self.gcc_bswap(step3, width) + } }, 128 => { // TODO(antoyo): find a more efficient implementation? diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index b59c3a64f57..9115cf97119 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -165,10 +165,15 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( InvalidMonomorphizationReturnIntegerType { span, name, ret_ty, out_ty } ); + let arg1 = args[0].immediate(); + // NOTE: we get different vector types for the same vector type and libgccjit doesn't + // compare them as equal, so bitcast. + // FIXME(antoyo): allow comparing vector types as equal in libgccjit. + let arg2 = bx.context.new_bitcast(None, args[1].immediate(), arg1.get_type()); return Ok(compare_simd_types( bx, - args[0].immediate(), - args[1].immediate(), + arg1, + arg2, in_elem, llret_ty, cmp_op, @@ -341,7 +346,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( // endian and MSB-first for big endian. let vector = args[0].immediate(); - let vector_type = vector.get_type().dyncast_vector().expect("vector type"); + // TODO(antoyo): dyncast_vector should not require a call to unqualified. + let vector_type = vector.get_type().unqualified().dyncast_vector().expect("vector type"); let elem_type = vector_type.get_element_type(); let expected_int_bits = in_len.max(8); @@ -848,7 +854,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( (true, true) => { // Algorithm from: https://codereview.stackexchange.com/questions/115869/saturated-signed-addition // TODO(antoyo): improve using conditional operators if possible. - let arg_type = lhs.get_type(); + // TODO(antoyo): dyncast_vector should not require a call to unqualified. + let arg_type = lhs.get_type().unqualified(); // TODO(antoyo): convert lhs and rhs to unsigned. let sum = lhs + rhs; let vector_type = arg_type.dyncast_vector().expect("vector type"); @@ -878,7 +885,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( res & cmp }, (true, false) => { - let arg_type = lhs.get_type(); + // TODO(antoyo): dyncast_vector should not require a call to unqualified. + let arg_type = lhs.get_type().unqualified(); // TODO(antoyo): this uses the same algorithm from saturating add, but add the // negative of the right operand. Find a proper subtraction algorithm. let rhs = bx.context.new_unary_op(None, UnaryOp::Minus, arg_type, rhs); diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index ea013c4428c..2a6b642782d 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -111,6 +111,8 @@ impl CodegenBackend for GccCodegenBackend { } fn init(&self, sess: &Session) { + #[cfg(feature="master")] + gccjit::set_global_personality_function_name(b"rust_eh_personality\0"); if sess.lto() != Lto::No { sess.emit_warning(LTONotSupported {}); } diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index 30a3fe67b85..74f016cf90a 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -383,8 +383,8 @@ impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { unimplemented!(); } - fn fn_decl_backend_type(&self, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> { - // FIXME(antoyo): return correct type. - self.type_void() + fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> { + let (return_type, param_types, variadic, _) = fn_abi.gcc_type(self); + self.context.new_function_pointer_type(None, return_type, ¶m_types, variadic) } } diff --git a/compiler/rustc_codegen_gcc/test.sh b/compiler/rustc_codegen_gcc/test.sh index 6139892aefc..592997b8ab9 100755 --- a/compiler/rustc_codegen_gcc/test.sh +++ b/compiler/rustc_codegen_gcc/test.sh @@ -214,12 +214,14 @@ function setup_rustc() { rm config.toml || true cat > config.toml <<EOF +changelog-seen = 2 + [rust] codegen-backends = [] deny-warnings = false [build] -cargo = "$(which cargo)" +cargo = "$(rustup which cargo)" local-rebuild = true rustc = "$HOME/.rustup/toolchains/$rust_toolchain-$TARGET_TRIPLE/bin/rustc" @@ -237,7 +239,7 @@ EOF function asm_tests() { setup_rustc - echo "[TEST] rustc test suite" + echo "[TEST] rustc asm test suite" RUSTC_ARGS="-Zpanic-abort-tests -Csymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext" --sysroot "$(pwd)"/../build_sysroot/sysroot -Cpanic=abort" COMPILETEST_FORCE_STAGE0=1 ./x.py test --run always --stage 0 tests/assembly/asm --rustc-args "$RUSTC_ARGS" } @@ -338,6 +340,8 @@ function test_rustc() { for test in $(rg -i --files-with-matches "//(\[\w+\])?~|// error-pattern:|// build-fail|// run-fail|-Cllvm-args" tests/ui); do rm $test done + rm tests/ui/consts/const_cmp_type_id.rs + rm tests/ui/consts/issue-73976-monomorphic.rs git checkout -- tests/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed diff --git a/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py b/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py index 6188924b0d5..83abe145e64 100644 --- a/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py +++ b/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py @@ -3,7 +3,6 @@ import os import re import sys import subprocess -from os import walk def run_command(command, cwd=None): @@ -180,7 +179,7 @@ def update_intrinsics(llvm_path, llvmint, llvmint2): intrinsics[arch].sort(key=lambda x: (x[0], x[2])) out.write(' // {}\n'.format(arch)) for entry in intrinsics[arch]: - if entry[2] == True: # if it is a duplicate + if entry[2] is True: # if it is a duplicate out.write(' // [DUPLICATE]: "{}" => "{}",\n'.format(entry[0], entry[1])) elif "_round_mask" in entry[1]: out.write(' // [INVALID CONVERSION]: "{}" => "{}",\n'.format(entry[0], entry[1])) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 1a8618e0c55..4b88ab8a97a 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1031,7 +1031,7 @@ fn build_upvar_field_di_nodes<'ll, 'tcx>( build_field_di_node( cx, closure_or_generator_di_node, - capture_name, + capture_name.as_str(), cx.size_and_align_of(up_var_ty), layout.fields.offset(index), DIFlags::FlagZero, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs index ecb0912d328..b2765ffc934 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs @@ -676,8 +676,7 @@ fn build_union_fields_for_direct_tag_generator<'ll, 'tcx>( _ => unreachable!(), }; - let (generator_layout, state_specific_upvar_names) = - cx.tcx.generator_layout_and_saved_local_names(generator_def_id); + let generator_layout = cx.tcx.optimized_mir(generator_def_id).generator_layout().unwrap(); let common_upvar_names = cx.tcx.closure_saved_names_of_captured_variables(generator_def_id); let variant_range = generator_substs.variant_range(generator_def_id, cx.tcx); @@ -714,7 +713,6 @@ fn build_union_fields_for_direct_tag_generator<'ll, 'tcx>( generator_type_and_layout, generator_type_di_node, generator_layout, - &state_specific_upvar_names, &common_upvar_names, ); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index 9e0e847a155..8746ce0c5b1 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -6,7 +6,7 @@ use rustc_hir::def::CtorKind; use rustc_index::IndexSlice; use rustc_middle::{ bug, - mir::{GeneratorLayout, GeneratorSavedLocal}, + mir::GeneratorLayout, ty::{ self, layout::{IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout}, @@ -323,8 +323,7 @@ pub fn build_generator_variant_struct_type_di_node<'ll, 'tcx>( generator_type_and_layout: TyAndLayout<'tcx>, generator_type_di_node: &'ll DIType, generator_layout: &GeneratorLayout<'tcx>, - state_specific_upvar_names: &IndexSlice<GeneratorSavedLocal, Option<Symbol>>, - common_upvar_names: &[String], + common_upvar_names: &IndexSlice<FieldIdx, Symbol>, ) -> &'ll DIType { let variant_name = GeneratorSubsts::variant_name(variant_index); let unique_type_id = UniqueTypeId::for_enum_variant_struct_type( @@ -357,7 +356,7 @@ pub fn build_generator_variant_struct_type_di_node<'ll, 'tcx>( .map(|field_index| { let generator_saved_local = generator_layout.variant_fields[variant_index] [FieldIdx::from_usize(field_index)]; - let field_name_maybe = state_specific_upvar_names[generator_saved_local]; + let field_name_maybe = generator_layout.field_names[generator_saved_local]; let field_name = field_name_maybe .as_ref() .map(|s| Cow::from(s.as_str())) @@ -380,12 +379,13 @@ pub fn build_generator_variant_struct_type_di_node<'ll, 'tcx>( // Fields that are common to all states let common_fields: SmallVec<_> = generator_substs .prefix_tys() + .zip(common_upvar_names) .enumerate() - .map(|(index, upvar_ty)| { + .map(|(index, (upvar_ty, upvar_name))| { build_field_di_node( cx, variant_struct_type_di_node, - &common_upvar_names[index], + upvar_name.as_str(), cx.size_and_align_of(upvar_ty), generator_type_and_layout.fields.offset(index), DIFlags::FlagZero, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs index 666b9762f5a..4d1cd64865f 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -155,8 +155,8 @@ pub(super) fn build_generator_di_node<'ll, 'tcx>( DIFlags::FlagZero, ), |cx, generator_type_di_node| { - let (generator_layout, state_specific_upvar_names) = - cx.tcx.generator_layout_and_saved_local_names(generator_def_id); + let generator_layout = + cx.tcx.optimized_mir(generator_def_id).generator_layout().unwrap(); let Variants::Multiple { tag_encoding: TagEncoding::Direct, ref variants, .. } = generator_type_and_layout.variants else { bug!( @@ -195,7 +195,6 @@ pub(super) fn build_generator_di_node<'ll, 'tcx>( generator_type_and_layout, generator_type_di_node, generator_layout, - &state_specific_upvar_names, &common_upvar_names, ), source_info, diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 109e9959aea..51ac441a7a4 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -11,9 +11,7 @@ use jobserver::{Acquired, Client}; use rustc_ast::attr; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::memmap::Mmap; -use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_data_structures::profiling::TimingGuard; -use rustc_data_structures::profiling::VerboseTimingGuard; +use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard}; use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::Emitter; use rustc_errors::{translation::Translate, DiagnosticId, FatalError, Handler, Level}; @@ -322,7 +320,6 @@ pub type ExportedSymbols = FxHashMap<CrateNum, Arc<Vec<(String, SymbolExportInfo #[derive(Clone)] pub struct CodegenContext<B: WriteBackendMethods> { // Resources needed when running LTO - pub backend: B, pub prof: SelfProfilerRef, pub lto: Lto, pub save_temps: bool, @@ -340,14 +337,10 @@ pub struct CodegenContext<B: WriteBackendMethods> { pub msvc_imps_needed: bool, pub is_pe_coff: bool, pub target_can_use_split_dwarf: bool, - pub target_pointer_width: u32, pub target_arch: String, - pub debuginfo: config::DebugInfo, pub split_debuginfo: rustc_target::spec::SplitDebuginfo, pub split_dwarf_kind: rustc_session::config::SplitDwarfKind, - /// Number of cgus excluding the allocator/metadata modules - pub total_cgus: usize, /// Handler to use for diagnostics produced during codegen. pub diag_emitter: SharedEmitter, /// LLVM optimizations for which we want to print remarks. @@ -443,7 +436,6 @@ pub fn start_async_codegen<B: ExtraBackendMethods>( target_cpu: String, metadata: EncodedMetadata, metadata_module: Option<CompiledModule>, - total_cgus: usize, ) -> OngoingCodegen<B> { let (coordinator_send, coordinator_receive) = channel(); let sess = tcx.sess; @@ -471,7 +463,6 @@ pub fn start_async_codegen<B: ExtraBackendMethods>( shared_emitter, codegen_worker_send, coordinator_receive, - total_cgus, sess.jobserver.clone(), Arc::new(regular_config), Arc::new(metadata_config), @@ -687,7 +678,7 @@ fn produce_final_output_artifacts( // These are used in linking steps and will be cleaned up afterward. } -pub enum WorkItem<B: WriteBackendMethods> { +pub(crate) enum WorkItem<B: WriteBackendMethods> { /// Optimize a newly codegened, totally unoptimized module. Optimize(ModuleCodegen<B::Module>), /// Copy the post-LTO artifacts from the incremental cache to the output @@ -705,20 +696,6 @@ impl<B: WriteBackendMethods> WorkItem<B> { } } - fn start_profiling<'a>(&self, cgcx: &'a CodegenContext<B>) -> TimingGuard<'a> { - match *self { - WorkItem::Optimize(ref m) => { - cgcx.prof.generic_activity_with_arg("codegen_module_optimize", &*m.name) - } - WorkItem::CopyPostLtoArtifacts(ref m) => cgcx - .prof - .generic_activity_with_arg("codegen_copy_artifacts_from_incr_cache", &*m.name), - WorkItem::LTO(ref m) => { - cgcx.prof.generic_activity_with_arg("codegen_module_perform_lto", m.name()) - } - } - } - /// Generate a short description of this work item suitable for use as a thread name. fn short_description(&self) -> String { // `pthread_setname()` on *nix is limited to 15 characters and longer names are ignored. @@ -747,7 +724,8 @@ impl<B: WriteBackendMethods> WorkItem<B> { } } -enum WorkItemResult<B: WriteBackendMethods> { +/// A result produced by the backend. +pub(crate) enum WorkItemResult<B: WriteBackendMethods> { Compiled(CompiledModule), NeedsLink(ModuleCodegen<B::Module>), NeedsFatLTO(FatLTOInput<B>), @@ -759,21 +737,6 @@ pub enum FatLTOInput<B: WriteBackendMethods> { InMemory(ModuleCodegen<B::Module>), } -fn execute_work_item<B: ExtraBackendMethods>( - cgcx: &CodegenContext<B>, - work_item: WorkItem<B>, -) -> Result<WorkItemResult<B>, FatalError> { - let module_config = cgcx.config(work_item.module_kind()); - - match work_item { - WorkItem::Optimize(module) => execute_optimize_work_item(cgcx, module, module_config), - WorkItem::CopyPostLtoArtifacts(module) => { - Ok(execute_copy_from_cache_work_item(cgcx, module, module_config)) - } - WorkItem::LTO(module) => execute_lto_work_item(cgcx, module, module_config), - } -} - /// Actual LTO type we end up choosing based on multiple factors. pub enum ComputedLtoType { No, @@ -954,38 +917,41 @@ fn finish_intra_module_work<B: ExtraBackendMethods>( } } -pub enum Message<B: WriteBackendMethods> { +/// Messages sent to the coordinator. +pub(crate) enum Message<B: WriteBackendMethods> { + /// A jobserver token has become available. Sent from the jobserver helper + /// thread. Token(io::Result<Acquired>), - NeedsFatLTO { - result: FatLTOInput<B>, - worker_id: usize, - }, - NeedsThinLTO { - name: String, - thin_buffer: B::ThinBuffer, - worker_id: usize, - }, - NeedsLink { - module: ModuleCodegen<B::Module>, - worker_id: usize, - }, - Done { - result: Result<CompiledModule, Option<WorkerFatalError>>, - worker_id: usize, - }, - CodegenDone { - llvm_work_item: WorkItem<B>, - cost: u64, - }, + + /// The backend has finished processing a work item for a codegen unit. + /// Sent from a backend worker thread. + WorkItem { result: Result<WorkItemResult<B>, Option<WorkerFatalError>>, worker_id: usize }, + + /// The frontend has finished generating something (backend IR or a + /// post-LTO artifact) for a codegen unit, and it should be passed to the + /// backend. Sent from the main thread. + CodegenDone { llvm_work_item: WorkItem<B>, cost: u64 }, + + /// Similar to `CodegenDone`, but for reusing a pre-LTO artifact + /// Sent from the main thread. AddImportOnlyModule { module_data: SerializedModule<B::ModuleBuffer>, work_product: WorkProduct, }, + + /// The frontend has finished generating everything for all codegen units. + /// Sent from the main thread. CodegenComplete, - CodegenItem, + + /// Some normal-ish compiler error occurred, and codegen should be wound + /// down. Sent from the main thread. CodegenAborted, } +/// A message sent from the coordinator thread to the main thread telling it to +/// process another codegen unit. +pub struct CguMessage; + type DiagnosticArgName<'source> = Cow<'source, str>; struct Diagnostic { @@ -1007,9 +973,8 @@ fn start_executing_work<B: ExtraBackendMethods>( tcx: TyCtxt<'_>, crate_info: &CrateInfo, shared_emitter: SharedEmitter, - codegen_worker_send: Sender<Message<B>>, + codegen_worker_send: Sender<CguMessage>, coordinator_receive: Receiver<Box<dyn Any + Send>>, - total_cgus: usize, jobserver: Client, regular_config: Arc<ModuleConfig>, metadata_config: Arc<ModuleConfig>, @@ -1077,7 +1042,6 @@ fn start_executing_work<B: ExtraBackendMethods>( }; let backend_features = tcx.global_backend_features(()); let cgcx = CodegenContext::<B> { - backend: backend.clone(), crate_types: sess.crate_types().to_vec(), each_linked_rlib_for_lto, lto: sess.lto(), @@ -1098,13 +1062,10 @@ fn start_executing_work<B: ExtraBackendMethods>( metadata_module_config: metadata_config, allocator_module_config: allocator_config, tm_factory: backend.target_machine_factory(tcx.sess, ol, backend_features), - total_cgus, msvc_imps_needed: msvc_imps_needed(tcx), is_pe_coff: tcx.sess.target.is_like_windows, target_can_use_split_dwarf: tcx.sess.target_can_use_split_dwarf(), - target_pointer_width: tcx.sess.target.pointer_width, target_arch: tcx.sess.target.arch.to_string(), - debuginfo: tcx.sess.opts.debuginfo, split_debuginfo: tcx.sess.split_debuginfo(), split_dwarf_kind: tcx.sess.opts.unstable_opts.split_dwarf_kind, }; @@ -1266,10 +1227,19 @@ fn start_executing_work<B: ExtraBackendMethods>( let mut needs_thin_lto = Vec::new(); let mut lto_import_only_modules = Vec::new(); let mut started_lto = false; - let mut codegen_aborted = false; - // This flag tracks whether all items have gone through codegens - let mut codegen_done = false; + /// Possible state transitions: + /// - Ongoing -> Completed + /// - Ongoing -> Aborted + /// - Completed -> Aborted + #[derive(Debug, PartialEq)] + enum CodegenState { + Ongoing, + Completed, + Aborted, + } + use CodegenState::*; + let mut codegen_state = Ongoing; // This is the queue of LLVM work items that still need processing. let mut work_items = Vec::<(WorkItem<B>, u64)>::new(); @@ -1289,10 +1259,10 @@ fn start_executing_work<B: ExtraBackendMethods>( // wait for all existing work to finish, so many of the conditions here // only apply if codegen hasn't been aborted as they represent pending // work to be done. - while !codegen_done + while codegen_state == Ongoing || running > 0 || main_thread_worker_state == MainThreadWorkerState::LLVMing - || (!codegen_aborted + || (codegen_state == Completed && !(work_items.is_empty() && needs_fat_lto.is_empty() && needs_thin_lto.is_empty() @@ -1302,7 +1272,7 @@ fn start_executing_work<B: ExtraBackendMethods>( // While there are still CGUs to be codegened, the coordinator has // to decide how to utilize the compiler processes implicit Token: // For codegenning more CGU or for running them through LLVM. - if !codegen_done { + if codegen_state == Ongoing { if main_thread_worker_state == MainThreadWorkerState::Idle { // Compute the number of workers that will be running once we've taken as many // items from the work queue as we can, plus one for the main thread. It's not @@ -1315,9 +1285,9 @@ fn start_executing_work<B: ExtraBackendMethods>( let anticipated_running = running + additional_running + 1; if !queue_full_enough(work_items.len(), anticipated_running) { - // The queue is not full enough, codegen more items: - if codegen_worker_send.send(Message::CodegenItem).is_err() { - panic!("Could not send Message::CodegenItem to main thread") + // The queue is not full enough, process more codegen units: + if codegen_worker_send.send(CguMessage).is_err() { + panic!("Could not send CguMessage to main thread") } main_thread_worker_state = MainThreadWorkerState::Codegenning; } else { @@ -1339,10 +1309,7 @@ fn start_executing_work<B: ExtraBackendMethods>( spawn_work(cgcx, item); } } - } else if codegen_aborted { - // don't queue up any more work if codegen was aborted, we're - // just waiting for our existing children to finish - } else { + } else if codegen_state == Completed { // If we've finished everything related to normal codegen // then it must be the case that we've got some LTO work to do. // Perform the serial work here of figuring out what we're @@ -1409,11 +1376,15 @@ fn start_executing_work<B: ExtraBackendMethods>( // Already making good use of that token } } + } else { + // Don't queue up any more work if codegen was aborted, we're + // just waiting for our existing children to finish. + assert!(codegen_state == Aborted); } // Spin up what work we can, only doing this while we've got available // parallelism slots and work left to spawn. - while !codegen_aborted && !work_items.is_empty() && running < tokens.len() { + while codegen_state != Aborted && !work_items.is_empty() && running < tokens.len() { let (item, _) = work_items.pop().unwrap(); maybe_start_llvm_timer(prof, cgcx.config(item.module_kind()), &mut llvm_start_time); @@ -1465,8 +1436,7 @@ fn start_executing_work<B: ExtraBackendMethods>( Err(e) => { let msg = &format!("failed to acquire jobserver token: {}", e); shared_emitter.fatal(msg); - codegen_done = true; - codegen_aborted = true; + codegen_state = Aborted; } } } @@ -1494,7 +1464,9 @@ fn start_executing_work<B: ExtraBackendMethods>( } Message::CodegenComplete => { - codegen_done = true; + if codegen_state != Aborted { + codegen_state = Completed; + } assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning); main_thread_worker_state = MainThreadWorkerState::Idle; } @@ -1506,58 +1478,59 @@ fn start_executing_work<B: ExtraBackendMethods>( // then conditions above will ensure no more work is spawned but // we'll keep executing this loop until `running` hits 0. Message::CodegenAborted => { - codegen_done = true; - codegen_aborted = true; + codegen_state = Aborted; } - Message::Done { result: Ok(compiled_module), worker_id } => { + + Message::WorkItem { result, worker_id } => { free_worker(worker_id); - match compiled_module.kind { - ModuleKind::Regular => { - compiled_modules.push(compiled_module); + + match result { + Ok(WorkItemResult::Compiled(compiled_module)) => { + match compiled_module.kind { + ModuleKind::Regular => { + compiled_modules.push(compiled_module); + } + ModuleKind::Allocator => { + assert!(compiled_allocator_module.is_none()); + compiled_allocator_module = Some(compiled_module); + } + ModuleKind::Metadata => bug!("Should be handled separately"), + } + } + Ok(WorkItemResult::NeedsLink(module)) => { + needs_link.push(module); + } + Ok(WorkItemResult::NeedsFatLTO(fat_lto_input)) => { + assert!(!started_lto); + needs_fat_lto.push(fat_lto_input); + } + Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer)) => { + assert!(!started_lto); + needs_thin_lto.push((name, thin_buffer)); } - ModuleKind::Allocator => { - assert!(compiled_allocator_module.is_none()); - compiled_allocator_module = Some(compiled_module); + Err(Some(WorkerFatalError)) => { + // Like `CodegenAborted`, wait for remaining work to finish. + codegen_state = Aborted; + } + Err(None) => { + // If the thread failed that means it panicked, so + // we abort immediately. + bug!("worker thread panicked"); } - ModuleKind::Metadata => bug!("Should be handled separately"), } } - Message::NeedsLink { module, worker_id } => { - free_worker(worker_id); - needs_link.push(module); - } - Message::NeedsFatLTO { result, worker_id } => { - assert!(!started_lto); - free_worker(worker_id); - needs_fat_lto.push(result); - } - Message::NeedsThinLTO { name, thin_buffer, worker_id } => { - assert!(!started_lto); - free_worker(worker_id); - needs_thin_lto.push((name, thin_buffer)); - } + Message::AddImportOnlyModule { module_data, work_product } => { assert!(!started_lto); - assert!(!codegen_done); + assert_eq!(codegen_state, Ongoing); assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning); lto_import_only_modules.push((module_data, work_product)); main_thread_worker_state = MainThreadWorkerState::Idle; } - // If the thread failed that means it panicked, so we abort immediately. - Message::Done { result: Err(None), worker_id: _ } => { - bug!("worker thread panicked"); - } - Message::Done { result: Err(Some(WorkerFatalError)), worker_id } => { - // Similar to CodegenAborted, wait for remaining work to finish. - free_worker(worker_id); - codegen_done = true; - codegen_aborted = true; - } - Message::CodegenItem => bug!("the coordinator should not receive codegen requests"), } } - if codegen_aborted { + if codegen_state == Aborted { return Err(()); } @@ -1672,22 +1645,11 @@ fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B> fn drop(&mut self) { let worker_id = self.worker_id; let msg = match self.result.take() { - Some(Ok(WorkItemResult::Compiled(m))) => { - Message::Done::<B> { result: Ok(m), worker_id } - } - Some(Ok(WorkItemResult::NeedsLink(m))) => { - Message::NeedsLink::<B> { module: m, worker_id } - } - Some(Ok(WorkItemResult::NeedsFatLTO(m))) => { - Message::NeedsFatLTO::<B> { result: m, worker_id } - } - Some(Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer))) => { - Message::NeedsThinLTO::<B> { name, thin_buffer, worker_id } - } + Some(Ok(result)) => Message::WorkItem::<B> { result: Ok(result), worker_id }, Some(Err(FatalError)) => { - Message::Done::<B> { result: Err(Some(WorkerFatalError)), worker_id } + Message::WorkItem::<B> { result: Err(Some(WorkerFatalError)), worker_id } } - None => Message::Done::<B> { result: Err(None), worker_id }, + None => Message::WorkItem::<B> { result: Err(None), worker_id }, }; drop(self.coordinator_send.send(Box::new(msg))); } @@ -1706,8 +1668,27 @@ fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B> // as a diagnostic was already sent off to the main thread - just // surface that there was an error in this worker. bomb.result = { - let _prof_timer = work.start_profiling(&cgcx); - Some(execute_work_item(&cgcx, work)) + let module_config = cgcx.config(work.module_kind()); + + Some(match work { + WorkItem::Optimize(m) => { + let _timer = + cgcx.prof.generic_activity_with_arg("codegen_module_optimize", &*m.name); + execute_optimize_work_item(&cgcx, m, module_config) + } + WorkItem::CopyPostLtoArtifacts(m) => { + let _timer = cgcx.prof.generic_activity_with_arg( + "codegen_copy_artifacts_from_incr_cache", + &*m.name, + ); + Ok(execute_copy_from_cache_work_item(&cgcx, m, module_config)) + } + WorkItem::LTO(m) => { + let _timer = + cgcx.prof.generic_activity_with_arg("codegen_module_perform_lto", m.name()); + execute_lto_work_item(&cgcx, m, module_config) + } + }) }; }) .expect("failed to spawn thread"); @@ -1891,7 +1872,7 @@ pub struct OngoingCodegen<B: ExtraBackendMethods> { pub metadata: EncodedMetadata, pub metadata_module: Option<CompiledModule>, pub crate_info: CrateInfo, - pub codegen_worker_receive: Receiver<Message<B>>, + pub codegen_worker_receive: Receiver<CguMessage>, pub shared_emitter_main: SharedEmitterMain, pub output_filenames: Arc<OutputFilenames>, pub coordinator: Coordinator<B>, @@ -1965,10 +1946,9 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> { pub fn wait_for_signal_to_codegen_item(&self) { match self.codegen_worker_receive.recv() { - Ok(Message::CodegenItem) => { - // Nothing to do + Ok(CguMessage) => { + // Ok to proceed. } - Ok(_) => panic!("unexpected message"), Err(_) => { // One of the LLVM threads must have panicked, fall through so // error handling can be reached. diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index dc4a28c866f..28f3c23364c 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -13,7 +13,7 @@ use crate::mir::place::PlaceRef; use crate::traits::*; use crate::{CachedModuleCodegen, CompiledModule, CrateInfo, MemFlags, ModuleCodegen, ModuleKind}; -use rustc_ast::expand::allocator::AllocatorKind; +use rustc_ast::expand::allocator::{global_fn_name, AllocatorKind, ALLOCATOR_METHODS}; use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; @@ -580,7 +580,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>( ) -> OngoingCodegen<B> { // Skip crate items and just output metadata in -Z no-codegen mode. if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() { - let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, metadata, None, 1); + let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, metadata, None); ongoing_codegen.codegen_finished(tcx); @@ -631,14 +631,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>( }) }); - let ongoing_codegen = start_async_codegen( - backend.clone(), - tcx, - target_cpu, - metadata, - metadata_module, - codegen_units.len(), - ); + let ongoing_codegen = + start_async_codegen(backend.clone(), tcx, target_cpu, metadata, metadata_module); // Codegen an allocator shim, if necessary. if let Some(kind) = allocator_kind_for_codegen(tcx) { @@ -921,7 +915,21 @@ impl CrateInfo { missing_weak_lang_items .iter() .map(|item| (format!("{prefix}{item}"), SymbolExportKind::Text)), - ) + ); + if tcx.allocator_kind(()).is_some() { + // At least one crate needs a global allocator. This crate may be placed + // after the crate that defines it in the linker order, in which case some + // linkers return an error. By adding the global allocator shim methods to + // the linked_symbols list, linking the generated symbols.o will ensure that + // circular dependencies involving the global allocator don't lead to linker + // errors. + linked_symbols.extend(ALLOCATOR_METHODS.iter().map(|method| { + ( + format!("{prefix}{}", global_fn_name(method.name).as_str()), + SymbolExportKind::Text, + ) + })); + } }); } diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index e1abb73a504..5a68075991f 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -132,7 +132,7 @@ pub fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // all shifts). For 32- and 64-bit types, this matches the semantics // of Java. (See related discussion on #1877 and #10183.) -pub fn build_unchecked_lshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( +pub fn build_masked_lshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, lhs: Bx::Value, rhs: Bx::Value, @@ -143,7 +143,7 @@ pub fn build_unchecked_lshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx.shl(lhs, rhs) } -pub fn build_unchecked_rshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( +pub fn build_masked_rshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, lhs_t: Ty<'tcx>, lhs: Bx::Value, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index a4a8aad8726..0cec560ba45 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1280,7 +1280,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { destination, target, unwind, - from_hir_call: _, + call_source: _, fn_span, } => self.codegen_call_terminator( helper, diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 9ac2424e76b..8a65dd593b8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -211,52 +211,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { args[1].val.unaligned_volatile_store(bx, dst); return; } - | sym::unchecked_shl - | sym::unchecked_shr - | sym::unchecked_add - | sym::unchecked_sub - | sym::unchecked_mul - | sym::exact_div => { + sym::exact_div => { let ty = arg_tys[0]; match int_type_width_signed(ty, bx.tcx()) { - Some((_width, signed)) => match name { - sym::exact_div => { - if signed { - bx.exactsdiv(args[0].immediate(), args[1].immediate()) - } else { - bx.exactudiv(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_shl => bx.shl(args[0].immediate(), args[1].immediate()), - sym::unchecked_shr => { - if signed { - bx.ashr(args[0].immediate(), args[1].immediate()) - } else { - bx.lshr(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_add => { - if signed { - bx.unchecked_sadd(args[0].immediate(), args[1].immediate()) - } else { - bx.unchecked_uadd(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_sub => { - if signed { - bx.unchecked_ssub(args[0].immediate(), args[1].immediate()) - } else { - bx.unchecked_usub(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_mul => { - if signed { - bx.unchecked_smul(args[0].immediate(), args[1].immediate()) - } else { - bx.unchecked_umul(args[0].immediate(), args[1].immediate()) - } + Some((_width, signed)) => { + if signed { + bx.exactsdiv(args[0].immediate(), args[1].immediate()) + } else { + bx.exactudiv(args[0].immediate(), args[1].immediate()) } - _ => bug!(), }, None => { bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty }); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 5241a5aee00..2d3d0ec68b8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -798,6 +798,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.add(lhs, rhs) } } + mir::BinOp::AddUnchecked => { + if is_signed { + bx.unchecked_sadd(lhs, rhs) + } else { + bx.unchecked_uadd(lhs, rhs) + } + } mir::BinOp::Sub => { if is_float { bx.fsub(lhs, rhs) @@ -805,6 +812,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.sub(lhs, rhs) } } + mir::BinOp::SubUnchecked => { + if is_signed { + bx.unchecked_ssub(lhs, rhs) + } else { + bx.unchecked_usub(lhs, rhs) + } + } mir::BinOp::Mul => { if is_float { bx.fmul(lhs, rhs) @@ -812,6 +826,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.mul(lhs, rhs) } } + mir::BinOp::MulUnchecked => { + if is_signed { + bx.unchecked_smul(lhs, rhs) + } else { + bx.unchecked_umul(lhs, rhs) + } + } mir::BinOp::Div => { if is_float { bx.fdiv(lhs, rhs) @@ -848,8 +869,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.inbounds_gep(llty, lhs, &[rhs]) } } - mir::BinOp::Shl => common::build_unchecked_lshift(bx, lhs, rhs), - mir::BinOp::Shr => common::build_unchecked_rshift(bx, input_ty, lhs, rhs), + mir::BinOp::Shl => common::build_masked_lshift(bx, lhs, rhs), + mir::BinOp::ShlUnchecked => { + let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs); + bx.shl(lhs, rhs) + } + mir::BinOp::Shr => common::build_masked_rshift(bx, input_ty, lhs, rhs), + mir::BinOp::ShrUnchecked => { + let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs); + if is_signed { bx.ashr(lhs, rhs) } else { bx.lshr(lhs, rhs) } + } mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index bf660c59cab..e99005316b3 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -210,6 +210,9 @@ const_eval_long_running = .label = the const evaluator is currently interpreting this expression .help = the constant being evaluated +const_eval_match_eq_non_const = cannot match on `{$ty}` in {const_eval_const_context}s + .note = `{$ty}` cannot be compared in compile-time, and therefore cannot be used in `match`es + const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id} const_eval_memory_access_test = memory access failed diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index eed3091d481..ca38cce710e 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -271,6 +271,18 @@ pub struct RawBytesNote { pub bytes: String, } +// FIXME(fee1-dead) do not use stringly typed `ConstContext` + +#[derive(Diagnostic)] +#[diag(const_eval_match_eq_non_const, code = "E0015")] +#[note] +pub struct NonConstMatchEq<'tcx> { + #[primary_span] + pub span: Span, + pub ty: Ty<'tcx>, + pub kind: ConstContext, +} + #[derive(Diagnostic)] #[diag(const_eval_for_loop_into_iter_non_const, code = "E0015")] pub struct NonConstForLoopIntoIter<'tcx> { diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 7192bbc00d5..8f4cf23770e 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -234,37 +234,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let r = self.read_immediate(&args[1])?; self.exact_div(&l, &r, dest)?; } - sym::unchecked_shl - | sym::unchecked_shr - | sym::unchecked_add - | sym::unchecked_sub - | sym::unchecked_mul => { - let l = self.read_immediate(&args[0])?; - let r = self.read_immediate(&args[1])?; - let bin_op = match intrinsic_name { - sym::unchecked_shl => BinOp::Shl, - sym::unchecked_shr => BinOp::Shr, - sym::unchecked_add => BinOp::Add, - sym::unchecked_sub => BinOp::Sub, - sym::unchecked_mul => BinOp::Mul, - _ => bug!(), - }; - let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, &l, &r)?; - if overflowed { - let layout = self.layout_of(substs.type_at(0))?; - let r_val = r.to_scalar().to_bits(layout.size)?; - if let sym::unchecked_shl | sym::unchecked_shr = intrinsic_name { - throw_ub_custom!( - fluent::const_eval_overflow_shift, - val = r_val, - name = intrinsic_name - ); - } else { - throw_ub_custom!(fluent::const_eval_overflow, name = intrinsic_name); - } - } - self.write_scalar(val, dest)?; - } sym::rotate_left | sym::rotate_right => { // rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW)) // rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW)) diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 7186148daf0..7bca7efdf5a 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -3,10 +3,13 @@ use rustc_middle::mir; use rustc_middle::mir::interpret::{InterpResult, Scalar}; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, FloatTy, Ty}; +use rustc_span::symbol::sym; use rustc_target::abi::Abi; use super::{ImmTy, Immediate, InterpCx, Machine, PlaceTy}; +use crate::fluent_generated as fluent; + impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Applies the binary operation `op` to the two operands and writes a tuple of the result /// and a boolean signifying the potential overflow to the destination. @@ -139,8 +142,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> InterpResult<'tcx, (Scalar<M::Provenance>, bool, Ty<'tcx>)> { use rustc_middle::mir::BinOp::*; + let throw_ub_on_overflow = match bin_op { + AddUnchecked => Some(sym::unchecked_add), + SubUnchecked => Some(sym::unchecked_sub), + MulUnchecked => Some(sym::unchecked_mul), + ShlUnchecked => Some(sym::unchecked_shl), + ShrUnchecked => Some(sym::unchecked_shr), + _ => None, + }; + // Shift ops can have an RHS with a different numeric type. - if bin_op == Shl || bin_op == Shr { + if matches!(bin_op, Shl | ShlUnchecked | Shr | ShrUnchecked) { let size = u128::from(left_layout.size.bits()); // Even if `r` is signed, we treat it as if it was unsigned (i.e., we use its // zero-extended form). This matches the codegen backend: @@ -155,6 +167,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // integers are maximally 128bits wide, so negative shifts *always* overflow and we have // consistent results for the same value represented at different bit widths. assert!(size <= 128); + let original_r = r; let overflow = r >= size; // The shift offset is implicitly masked to the type size, to make sure this operation // is always defined. This is the one MIR operator that does *not* directly map to a @@ -166,19 +179,28 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let result = if left_layout.abi.is_signed() { let l = self.sign_extend(l, left_layout) as i128; let result = match bin_op { - Shl => l.checked_shl(r).unwrap(), - Shr => l.checked_shr(r).unwrap(), + Shl | ShlUnchecked => l.checked_shl(r).unwrap(), + Shr | ShrUnchecked => l.checked_shr(r).unwrap(), _ => bug!(), }; result as u128 } else { match bin_op { - Shl => l.checked_shl(r).unwrap(), - Shr => l.checked_shr(r).unwrap(), + Shl | ShlUnchecked => l.checked_shl(r).unwrap(), + Shr | ShrUnchecked => l.checked_shr(r).unwrap(), _ => bug!(), } }; let truncated = self.truncate(result, left_layout); + + if overflow && let Some(intrinsic_name) = throw_ub_on_overflow { + throw_ub_custom!( + fluent::const_eval_overflow_shift, + val = original_r, + name = intrinsic_name + ); + } + return Ok((Scalar::from_uint(truncated, left_layout.size), overflow, left_layout.ty)); } @@ -216,9 +238,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Rem if r == 0 => throw_ub!(RemainderByZero), Div => Some(i128::overflowing_div), Rem => Some(i128::overflowing_rem), - Add => Some(i128::overflowing_add), - Sub => Some(i128::overflowing_sub), - Mul => Some(i128::overflowing_mul), + Add | AddUnchecked => Some(i128::overflowing_add), + Sub | SubUnchecked => Some(i128::overflowing_sub), + Mul | MulUnchecked => Some(i128::overflowing_mul), _ => None, }; if let Some(op) = op { @@ -242,11 +264,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // If that truncation loses any information, we have an overflow. let result = result as u128; let truncated = self.truncate(result, left_layout); - return Ok(( - Scalar::from_uint(truncated, size), - oflo || self.sign_extend(truncated, left_layout) != result, - left_layout.ty, - )); + let overflow = oflo || self.sign_extend(truncated, left_layout) != result; + if overflow && let Some(intrinsic_name) = throw_ub_on_overflow { + throw_ub_custom!(fluent::const_eval_overflow, name = intrinsic_name); + } + return Ok((Scalar::from_uint(truncated, size), overflow, left_layout.ty)); } } @@ -263,12 +285,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { BitAnd => (Scalar::from_uint(l & r, size), left_layout.ty), BitXor => (Scalar::from_uint(l ^ r, size), left_layout.ty), - Add | Sub | Mul | Rem | Div => { + Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Rem | Div => { assert!(!left_layout.abi.is_signed()); let op: fn(u128, u128) -> (u128, bool) = match bin_op { - Add => u128::overflowing_add, - Sub => u128::overflowing_sub, - Mul => u128::overflowing_mul, + Add | AddUnchecked => u128::overflowing_add, + Sub | SubUnchecked => u128::overflowing_sub, + Mul | MulUnchecked => u128::overflowing_mul, Div if r == 0 => throw_ub!(DivisionByZero), Rem if r == 0 => throw_ub!(RemainderByZero), Div => u128::overflowing_div, @@ -279,11 +301,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Truncate to target type. // If that truncation loses any information, we have an overflow. let truncated = self.truncate(result, left_layout); - return Ok(( - Scalar::from_uint(truncated, size), - oflo || truncated != result, - left_layout.ty, - )); + let overflow = oflo || truncated != result; + if overflow && let Some(intrinsic_name) = throw_ub_on_overflow { + throw_ub_custom!(fluent::const_eval_overflow, name = intrinsic_name); + } + return Ok((Scalar::from_uint(truncated, size), overflow, left_layout.ty)); } _ => span_bug!( diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 1e60a1e72ea..619da8abb7d 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -9,27 +9,7 @@ use rustc_middle::mir::interpret::{InterpResult, Scalar}; use rustc_middle::ty::layout::LayoutOf; use super::{ImmTy, InterpCx, Machine}; - -/// Classify whether an operator is "left-homogeneous", i.e., the LHS has the -/// same type as the result. -#[inline] -fn binop_left_homogeneous(op: mir::BinOp) -> bool { - use rustc_middle::mir::BinOp::*; - match op { - Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Offset | Shl | Shr => true, - Eq | Ne | Lt | Le | Gt | Ge => false, - } -} -/// Classify whether an operator is "right-homogeneous", i.e., the RHS has the -/// same type as the LHS. -#[inline] -fn binop_right_homogeneous(op: mir::BinOp) -> bool { - use rustc_middle::mir::BinOp::*; - match op { - Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge => true, - Offset | Shl | Shr => false, - } -} +use crate::util; impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Returns `true` as long as there are more things to do. @@ -179,9 +159,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } BinaryOp(bin_op, box (ref left, ref right)) => { - let layout = binop_left_homogeneous(bin_op).then_some(dest.layout); + let layout = util::binop_left_homogeneous(bin_op).then_some(dest.layout); let left = self.read_immediate(&self.eval_operand(left, layout)?)?; - let layout = binop_right_homogeneous(bin_op).then_some(left.layout); + let layout = util::binop_right_homogeneous(bin_op).then_some(left.layout); let right = self.read_immediate(&self.eval_operand(right, layout)?)?; self.binop_ignore_overflow(bin_op, &left, &right, &dest)?; } @@ -189,7 +169,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { CheckedBinaryOp(bin_op, box (ref left, ref right)) => { // Due to the extra boolean in the result, we can never reuse the `dest.layout`. let left = self.read_immediate(&self.eval_operand(left, None)?)?; - let layout = binop_right_homogeneous(bin_op).then_some(left.layout); + let layout = util::binop_right_homogeneous(bin_op).then_some(left.layout); let right = self.read_immediate(&self.eval_operand(right, layout)?)?; self.binop_with_overflow(bin_op, &left, &right, &dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 7269ff8d53c..719d8a14b41 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -62,7 +62,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { destination, target, unwind, - from_hir_call: _, + call_source: _, fn_span: _, } => { let old_stack = self.frame_idx(); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 106cf111474..33c79ad7e55 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -412,7 +412,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { BorrowKind::Shallow => { PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) } - BorrowKind::Unique => PlaceContext::MutatingUse(MutatingUseContext::Borrow), BorrowKind::Mut { .. } => { PlaceContext::MutatingUse(MutatingUseContext::Borrow) } @@ -457,7 +456,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } - Rvalue::Ref(_, kind @ (BorrowKind::Mut { .. } | BorrowKind::Unique), place) => { + Rvalue::Ref(_, BorrowKind::Mut { .. }, place) => { let ty = place.ty(self.body, self.tcx).ty; let is_allowed = match ty.kind() { // Inside a `static mut`, `&mut [...]` is allowed. @@ -478,11 +477,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { }; if !is_allowed { - if let BorrowKind::Mut { .. } = kind { - self.check_mut_borrow(place.local, hir::BorrowKind::Ref) - } else { - self.check_op(ops::CellBorrow); - } + self.check_mut_borrow(place.local, hir::BorrowKind::Ref) } } @@ -702,7 +697,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { self.super_terminator(terminator, location); match &terminator.kind { - TerminatorKind::Call { func, args, fn_span, from_hir_call, .. } => { + TerminatorKind::Call { func, args, fn_span, call_source, .. } => { let ConstCx { tcx, body, param_env, .. } = *self.ccx; let caller = self.def_id(); @@ -755,7 +750,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { callee, substs, span: *fn_span, - from_hir_call: *from_hir_call, + call_source: *call_source, feature: Some(sym::const_trait_impl), }); return; @@ -797,7 +792,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { callee, substs, span: *fn_span, - from_hir_call: *from_hir_call, + call_source: *call_source, feature: None, }); @@ -823,7 +818,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { callee, substs, span: *fn_span, - from_hir_call: *from_hir_call, + call_source: *call_source, feature: None, }); return; @@ -866,7 +861,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { callee, substs, span: *fn_span, - from_hir_call: *from_hir_call, + call_source: *call_source, feature: None, }); return; @@ -926,7 +921,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { callee, substs, span: *fn_span, - from_hir_call: *from_hir_call, + call_source: *call_source, feature: None, }); return; diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 236e43bdfcc..32bd9cda6f2 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -7,7 +7,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{ImplSource, Obligation, ObligationCause}; -use rustc_middle::mir; +use rustc_middle::mir::{self, CallSource}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::{suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, Ty}; @@ -100,7 +100,7 @@ pub struct FnCallNonConst<'tcx> { pub callee: DefId, pub substs: SubstsRef<'tcx>, pub span: Span, - pub from_hir_call: bool, + pub call_source: CallSource, pub feature: Option<Symbol>, } @@ -110,7 +110,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { ccx: &ConstCx<'_, 'tcx>, _: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let FnCallNonConst { caller, callee, substs, span, from_hir_call, feature } = *self; + let FnCallNonConst { caller, callee, substs, span, call_source, feature } = *self; let ConstCx { tcx, param_env, .. } = *ccx; let diag_trait = |err, self_ty: Ty<'_>, trait_id| { @@ -157,7 +157,8 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { } }; - let call_kind = call_kind(tcx, ccx.param_env, callee, substs, span, from_hir_call, None); + let call_kind = + call_kind(tcx, ccx.param_env, callee, substs, span, call_source.from_hir_call(), None); debug!(?call_kind); @@ -219,48 +220,59 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { err } CallKind::Operator { trait_id, self_ty, .. } => { - let mut sugg = None; - - if Some(trait_id) == ccx.tcx.lang_items().eq_trait() { - match (substs[0].unpack(), substs[1].unpack()) { - (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty)) - if self_ty == rhs_ty - && self_ty.is_ref() - && self_ty.peel_refs().is_primitive() => - { - let mut num_refs = 0; - let mut tmp_ty = self_ty; - while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() { - num_refs += 1; - tmp_ty = *inner_ty; - } - let deref = "*".repeat(num_refs); - - if let Ok(call_str) = ccx.tcx.sess.source_map().span_to_snippet(span) { - if let Some(eq_idx) = call_str.find("==") { - if let Some(rhs_idx) = - call_str[(eq_idx + 2)..].find(|c: char| !c.is_whitespace()) - { - let rhs_pos = - span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx); - let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos); - sugg = Some(errors::ConsiderDereferencing { - deref, - span: span.shrink_to_lo(), - rhs_span, - }); + let mut err = if let CallSource::MatchCmp = call_source { + tcx.sess.create_err(errors::NonConstMatchEq { + span, + kind: ccx.const_kind(), + ty: self_ty, + }) + } else { + let mut sugg = None; + + if Some(trait_id) == ccx.tcx.lang_items().eq_trait() { + match (substs[0].unpack(), substs[1].unpack()) { + (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty)) + if self_ty == rhs_ty + && self_ty.is_ref() + && self_ty.peel_refs().is_primitive() => + { + let mut num_refs = 0; + let mut tmp_ty = self_ty; + while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() { + num_refs += 1; + tmp_ty = *inner_ty; + } + let deref = "*".repeat(num_refs); + + if let Ok(call_str) = + ccx.tcx.sess.source_map().span_to_snippet(span) + { + if let Some(eq_idx) = call_str.find("==") { + if let Some(rhs_idx) = call_str[(eq_idx + 2)..] + .find(|c: char| !c.is_whitespace()) + { + let rhs_pos = span.lo() + + BytePos::from_usize(eq_idx + 2 + rhs_idx); + let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos); + sugg = Some(errors::ConsiderDereferencing { + deref, + span: span.shrink_to_lo(), + rhs_span, + }); + } } } } + _ => {} } - _ => {} } - } - let mut err = tcx.sess.create_err(errors::NonConstOperator { - span, - kind: ccx.const_kind(), - sugg, - }); + tcx.sess.create_err(errors::NonConstOperator { + span, + kind: ccx.const_kind(), + sugg, + }) + }; + diag_trait(&mut err, self_ty, trait_id); err } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs index 65fe164f8ec..3a869f7f547 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs @@ -103,7 +103,7 @@ where fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool { match kind { mir::BorrowKind::Mut { .. } => true, - mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => { + mir::BorrowKind::Shared | mir::BorrowKind::Shallow => { self.shared_borrow_allows_mutation(place) } } diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 44b143c77f3..dd80f745c2f 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -454,7 +454,9 @@ impl<'tcx> Validator<'_, 'tcx> { match kind { // Reject these borrow types just to be safe. // FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase. - BorrowKind::Shallow | BorrowKind::Unique => return Err(Unpromotable), + BorrowKind::Shallow | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => { + return Err(Unpromotable); + } BorrowKind::Shared => { let has_mut_interior = self.qualif_local::<qualifs::HasMutInterior>(place.local); @@ -463,7 +465,9 @@ impl<'tcx> Validator<'_, 'tcx> { } } - BorrowKind::Mut { .. } => { + // FIXME: consider changing this to only promote &mut [] for default borrows, + // also forbidding two phase borrows + BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow } => { let ty = place.ty(self.body, self.tcx).ty; // In theory, any zero-sized value could be borrowed @@ -569,13 +573,18 @@ impl<'tcx> Validator<'_, 'tcx> { | BinOp::Gt | BinOp::Offset | BinOp::Add + | BinOp::AddUnchecked | BinOp::Sub + | BinOp::SubUnchecked | BinOp::Mul + | BinOp::MulUnchecked | BinOp::BitXor | BinOp::BitAnd | BinOp::BitOr | BinOp::Shl - | BinOp::Shr => {} + | BinOp::ShlUnchecked + | BinOp::Shr + | BinOp::ShrUnchecked => {} } self.validate_operand(lhs)?; @@ -792,7 +801,9 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { }; match terminator.kind { - TerminatorKind::Call { mut func, mut args, from_hir_call, fn_span, .. } => { + TerminatorKind::Call { + mut func, mut args, call_source: desugar, fn_span, .. + } => { self.visit_operand(&mut func, loc); for arg in &mut args { self.visit_operand(arg, loc); @@ -808,7 +819,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { unwind: UnwindAction::Continue, destination: Place::from(new_temp), target: Some(new_target), - from_hir_call, + call_source: desugar, fn_span, }, source_info: SourceInfo::outermost(terminator.source_info.span), diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 3c350e25ba6..f197541da5b 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -498,8 +498,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { macro_rules! check_kinds { - ($t:expr, $text:literal, $($patterns:tt)*) => { - if !matches!(($t).kind(), $($patterns)*) { + ($t:expr, $text:literal, $typat:pat) => { + if !matches!(($t).kind(), $typat) { self.fail(location, format!($text, $t)); } }; @@ -527,6 +527,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { use BinOp::*; let a = vals.0.ty(&self.body.local_decls, self.tcx); let b = vals.1.ty(&self.body.local_decls, self.tcx); + if crate::util::binop_right_homogeneous(*op) { + if let Eq | Lt | Le | Ne | Ge | Gt = op { + // The function pointer types can have lifetimes + if !self.mir_assign_valid_types(a, b) { + self.fail( + location, + format!("Cannot {op:?} compare incompatible types {a:?} and {b:?}"), + ); + } + } else if a != b { + self.fail( + location, + format!( + "Cannot perform binary op {op:?} on unequal types {a:?} and {b:?}" + ), + ); + } + } + match op { Offset => { check_kinds!(a, "Cannot offset non-pointer type {:?}", ty::RawPtr(..)); @@ -538,7 +557,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { for x in [a, b] { check_kinds!( x, - "Cannot compare type {:?}", + "Cannot {op:?} compare type {:?}", ty::Bool | ty::Char | ty::Int(..) @@ -548,19 +567,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { | ty::FnPtr(..) ) } - // The function pointer types can have lifetimes - if !self.mir_assign_valid_types(a, b) { - self.fail( - location, - format!("Cannot compare unequal types {:?} and {:?}", a, b), - ); - } } - Shl | Shr => { + AddUnchecked | SubUnchecked | MulUnchecked | Shl | ShlUnchecked | Shr + | ShrUnchecked => { for x in [a, b] { check_kinds!( x, - "Cannot shift non-integer type {:?}", + "Cannot {op:?} non-integer type {:?}", ty::Uint(..) | ty::Int(..) ) } @@ -569,37 +582,19 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { for x in [a, b] { check_kinds!( x, - "Cannot perform bitwise op on type {:?}", + "Cannot perform bitwise op {op:?} on type {:?}", ty::Uint(..) | ty::Int(..) | ty::Bool ) } - if a != b { - self.fail( - location, - format!( - "Cannot perform bitwise op on unequal types {:?} and {:?}", - a, b - ), - ); - } } Add | Sub | Mul | Div | Rem => { for x in [a, b] { check_kinds!( x, - "Cannot perform arithmetic on type {:?}", + "Cannot perform arithmetic {op:?} on type {:?}", ty::Uint(..) | ty::Int(..) | ty::Float(..) ) } - if a != b { - self.fail( - location, - format!( - "Cannot perform arithmetic on unequal types {:?} and {:?}", - a, b - ), - ); - } } } } diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs index 7641f560714..289e3422595 100644 --- a/compiler/rustc_const_eval/src/util/mod.rs +++ b/compiler/rustc_const_eval/src/util/mod.rs @@ -1,3 +1,5 @@ +use rustc_middle::mir; + mod alignment; mod check_validity_requirement; mod compare_types; @@ -7,3 +9,27 @@ pub use self::alignment::is_disaligned; pub use self::check_validity_requirement::check_validity_requirement; pub use self::compare_types::{is_equal_up_to_subtyping, is_subtype}; pub use self::type_name::type_name; + +/// Classify whether an operator is "left-homogeneous", i.e., the LHS has the +/// same type as the result. +#[inline] +pub(crate) fn binop_left_homogeneous(op: mir::BinOp) -> bool { + use rustc_middle::mir::BinOp::*; + match op { + Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor + | BitAnd | BitOr | Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => true, + Eq | Ne | Lt | Le | Gt | Ge => false, + } +} + +/// Classify whether an operator is "right-homogeneous", i.e., the RHS has the +/// same type as the LHS. +#[inline] +pub(crate) fn binop_right_homogeneous(op: mir::BinOp) -> bool { + use rustc_middle::mir::BinOp::*; + match op { + Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor + | BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge => true, + Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => false, + } +} diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index 0c1fb7518fa..6d75b0fb8a0 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -1,6 +1,6 @@ use crate::sip128::SipHasher128; use rustc_index::bit_set::{self, BitSet}; -use rustc_index::{Idx, IndexVec}; +use rustc_index::{Idx, IndexSlice, IndexVec}; use smallvec::SmallVec; use std::fmt; use std::hash::{BuildHasher, Hash, Hasher}; @@ -597,6 +597,18 @@ where } } +impl<I: Idx, T, CTX> HashStable<CTX> for IndexSlice<I, T> +where + T: HashStable<CTX>, +{ + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for v in &self.raw { + v.hash_stable(ctx, hasher); + } + } +} + impl<I: Idx, T, CTX> HashStable<CTX> for IndexVec<I, T> where T: HashStable<CTX>, diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index e18c7b415f6..2b21815b687 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -107,6 +107,10 @@ impl<T, I: Iterator<Item = T>> UnordItems<T, I> { { UnordItems(self.0.flat_map(f)) } + + pub fn collect<C: From<UnordItems<T, I>>>(self) -> C { + self.into() + } } impl<T> UnordItems<T, std::iter::Empty<T>> { @@ -161,10 +165,6 @@ impl<T: Ord, I: Iterator<Item = T>> UnordItems<T, I> { items.sort_by_cached_key(|x| x.to_stable_hash_key(hcx)); items } - - pub fn collect<C: From<UnordItems<T, I>>>(self) -> C { - self.into() - } } /// This is a set collection type that tries very hard to not expose diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 2f1c7819727..984cc1557a4 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -97,6 +97,7 @@ pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[ rustc_codegen_ssa::DEFAULT_LOCALE_RESOURCE, rustc_const_eval::DEFAULT_LOCALE_RESOURCE, rustc_error_messages::DEFAULT_LOCALE_RESOURCE, + rustc_errors::DEFAULT_LOCALE_RESOURCE, rustc_expand::DEFAULT_LOCALE_RESOURCE, rustc_hir_analysis::DEFAULT_LOCALE_RESOURCE, rustc_hir_typeck::DEFAULT_LOCALE_RESOURCE, @@ -329,7 +330,7 @@ fn run_compiler( return; } let should_stop = - print_crate_info(&***compiler.codegen_backend(), compiler.session(), false); + print_crate_info(&**compiler.codegen_backend(), compiler.session(), false); if should_stop == Compilation::Stop { return; @@ -351,7 +352,7 @@ fn run_compiler( interface::run_compiler(config, |compiler| { let sess = compiler.session(); - let should_stop = print_crate_info(&***compiler.codegen_backend(), sess, true) + let should_stop = print_crate_info(&**compiler.codegen_backend(), sess, true) .and_then(|| list_metadata(sess, &*compiler.codegen_backend().metadata_loader())) .and_then(|| try_process_rlink(sess, compiler)); @@ -424,7 +425,7 @@ fn run_compiler( return early_exit(); } - queries.ongoing_codegen()?; + let ongoing_codegen = queries.ongoing_codegen()?; if sess.opts.unstable_opts.print_type_sizes { sess.code_stats.print_type_sizes(); @@ -437,7 +438,7 @@ fn run_compiler( sess.code_stats.print_vtable_sizes(crate_name); } - let linker = queries.linker()?; + let linker = queries.linker(ongoing_codegen)?; Ok(Some(linker)) })?; diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index ee9616a0f0a..4a8a14994ff 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -535,7 +535,7 @@ pub fn compile_declarative_macro( .pop() .unwrap(); } - sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") + sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs") }) .collect::<Vec<mbe::TokenTree>>(), _ => sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs"), diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 4c53f9d8369..93f968aa851 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -395,6 +395,8 @@ declare_features! ( (active, exclusive_range_pattern, "1.11.0", Some(37854), None), /// Allows exhaustive pattern matching on types that contain uninhabited types. (active, exhaustive_patterns, "1.13.0", Some(51085), None), + /// Allows explicit tail calls via `become` expression. + (incomplete, explicit_tail_calls, "CURRENT_RUSTC_VERSION", Some(112788), None), /// Allows using `efiapi`, `sysv64` and `win64` as calling convention /// for functions with varargs. (active, extended_varargs_abi_support, "1.65.0", Some(100189), None), @@ -440,6 +442,8 @@ declare_features! ( (active, intra_doc_pointers, "1.51.0", Some(80896), None), // Allows setting the threshold for the `large_assignments` lint. (active, large_assignments, "1.52.0", Some(83518), None), + /// Allow to have type alias types for inter-crate use. + (active, lazy_type_alias, "CURRENT_RUSTC_VERSION", Some(112792), None), /// Allows `if/while p && let q = r && ...` chains. (active, let_chains, "1.37.0", Some(53667), None), /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 9be28c338f6..3c5bff3812a 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -705,7 +705,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ "#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl." ), rustc_attr!( - rustc_deny_explicit_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: false, + rustc_deny_explicit_impl, + AttributeType::Normal, + template!(List: "implement_via_object = (true|false)"), + ErrorFollowing, + @only_local: true, "#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls" ), rustc_attr!( diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 70fc66947df..5e5001bc8b4 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3743,6 +3743,29 @@ impl<'hir> Node<'hir> { } } + /// Get the type for constants, assoc types, type aliases and statics. + pub fn ty(self) -> Option<&'hir Ty<'hir>> { + match self { + Node::Item(it) => match it.kind { + ItemKind::TyAlias(ty, _) | ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _) => { + Some(ty) + } + _ => None, + }, + Node::TraitItem(it) => match it.kind { + TraitItemKind::Const(ty, _) => Some(ty), + TraitItemKind::Type(_, ty) => ty, + _ => None, + }, + Node::ImplItem(it) => match it.kind { + ImplItemKind::Const(ty, _) => Some(ty), + ImplItemKind::Type(ty) => Some(ty), + _ => None, + }, + _ => None, + } + } + pub fn alias_ty(self) -> Option<&'hir Ty<'hir>> { match self { Node::Item(Item { kind: ItemKind::TyAlias(ty, ..), .. }) => Some(ty), diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index e4eb0e6abd4..d29601e9008 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -412,7 +412,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { // an RPITIT (return-position impl trait in trait) or AFIT (async fn in trait). let output = tcx.fn_sig(assoc_item.def_id).skip_binder().output(); let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind() - && tcx.def_kind(alias_ty.def_id) == DefKind::ImplTraitPlaceholder + && tcx.is_impl_trait_in_trait(alias_ty.def_id) { alias_ty } else { diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index 7b922f5d525..dc17ef7048d 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -122,9 +122,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let all_candidate_names: Vec<_> = all_candidates() .flat_map(|r| self.tcx().associated_items(r.def_id()).in_definition_order()) - .filter_map( - |item| if item.kind == ty::AssocKind::Type { Some(item.name) } else { None }, - ) + .filter_map(|item| { + if item.opt_rpitit_info.is_none() && item.kind == ty::AssocKind::Type { + Some(item.name) + } else { + None + } + }) .collect(); if let (Some(suggested_name), true) = ( @@ -159,9 +163,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .flat_map(|trait_def_id| { self.tcx().associated_items(*trait_def_id).in_definition_order() }) - .filter_map( - |item| if item.kind == ty::AssocKind::Type { Some(item.name) } else { None }, - ) + .filter_map(|item| { + if item.opt_rpitit_info.is_none() && item.kind == ty::AssocKind::Type { + Some(item.name) + } else { + None + } + }) .collect(); if let (Some(suggested_name), true) = ( @@ -343,7 +351,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let format_pred = |pred: ty::Predicate<'tcx>| { let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { let pred = bound_predicate.rebind(pred); // `<Foo as Iterator>::Item = String`. let projection_ty = pred.skip_binder().projection_ty; @@ -364,7 +372,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { bound_span_label(projection_ty.self_ty(), &obligation, &quiet); Some((obligation, projection_ty.self_ty())) } - ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_ref)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(poly_trait_ref)) => { let p = poly_trait_ref.trait_ref; let self_ty = p.self_ty(); let path = p.print_only_trait_path(); diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 621569ab321..41a6d94b278 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -896,7 +896,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let ty = self.tcx().at(span).type_of(did); if matches!(self.tcx().def_kind(did), DefKind::TyAlias) - && ty.skip_binder().has_opaque_types() + && (ty.skip_binder().has_opaque_types() || self.tcx().features().lazy_type_alias) { // Type aliases referring to types that contain opaque types (but aren't just directly // referencing a single opaque type) get encoded as a type alias that normalization will @@ -945,12 +945,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut trait_bounds = vec![]; let mut projection_bounds = vec![]; - for (clause, span) in bounds.predicates() { - let pred: ty::Predicate<'tcx> = clause.to_predicate(tcx); + for (clause, span) in bounds.clauses() { + let pred: ty::Predicate<'tcx> = clause.as_predicate(); let bound_pred = pred.kind(); match bound_pred.skip_binder() { ty::PredicateKind::Clause(clause) => match clause { - ty::Clause::Trait(trait_pred) => { + ty::ClauseKind::Trait(trait_pred) => { assert_eq!(trait_pred.polarity, ty::ImplPolarity::Positive); trait_bounds.push(( bound_pred.rebind(trait_pred.trait_ref), @@ -958,16 +958,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_pred.constness, )); } - ty::Clause::Projection(proj) => { + ty::ClauseKind::Projection(proj) => { projection_bounds.push((bound_pred.rebind(proj), span)); } - ty::Clause::TypeOutlives(_) => { + ty::ClauseKind::TypeOutlives(_) => { // Do nothing, we deal with regions separately } - ty::Clause::RegionOutlives(_) - | ty::Clause::ConstArgHasType(..) - | ty::Clause::WellFormed(_) - | ty::Clause::ConstEvaluatable(_) => bug!(), + ty::ClauseKind::RegionOutlives(_) + | ty::ClauseKind::ConstArgHasType(..) + | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::ConstEvaluatable(_) => { + bug!() + } }, ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ObjectSafe(_) @@ -1064,7 +1066,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { let pred = bound_predicate.rebind(pred); associated_types.entry(span).or_default().extend( tcx.associated_items(pred.def_id()) @@ -1074,7 +1076,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .map(|item| item.def_id), ); } - ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { let pred = bound_predicate.rebind(pred); // A `Self` within the original bound will be substituted with a // `trait_object_dummy_self`, so check for that. diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index 8a318e984d7..531100e1fe6 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -2,7 +2,6 @@ //! `ty` form from the HIR. use rustc_hir::LangItem; -use rustc_middle::ty::Binder; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; use rustc_span::Span; @@ -24,58 +23,58 @@ use rustc_span::Span; /// include the self type (e.g., `trait_bounds`) but in others we do not #[derive(Default, PartialEq, Eq, Clone, Debug)] pub struct Bounds<'tcx> { - pub predicates: Vec<(Binder<'tcx, ty::Clause<'tcx>>, Span)>, + pub clauses: Vec<(ty::Clause<'tcx>, Span)>, } impl<'tcx> Bounds<'tcx> { pub fn push_region_bound( &mut self, - _tcx: TyCtxt<'tcx>, + tcx: TyCtxt<'tcx>, region: ty::PolyTypeOutlivesPredicate<'tcx>, span: Span, ) { - self.predicates.push((region.map_bound(|p| ty::Clause::TypeOutlives(p)), span)); + self.clauses + .push((region.map_bound(|p| ty::ClauseKind::TypeOutlives(p)).to_predicate(tcx), span)); } pub fn push_trait_bound( &mut self, - _tcx: TyCtxt<'tcx>, + tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, span: Span, constness: ty::BoundConstness, polarity: ty::ImplPolarity, ) { - self.predicates.push(( - trait_ref.map_bound(|trait_ref| { - ty::Clause::Trait(ty::TraitPredicate { trait_ref, constness, polarity }) - }), + self.clauses.push(( + trait_ref + .map_bound(|trait_ref| { + ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, constness, polarity }) + }) + .to_predicate(tcx), span, )); } pub fn push_projection_bound( &mut self, - _tcx: TyCtxt<'tcx>, + tcx: TyCtxt<'tcx>, projection: ty::PolyProjectionPredicate<'tcx>, span: Span, ) { - self.predicates.push((projection.map_bound(|proj| ty::Clause::Projection(proj)), span)); + self.clauses.push(( + projection.map_bound(|proj| ty::ClauseKind::Projection(proj)).to_predicate(tcx), + span, + )); } pub fn push_sized(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) { let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span)); let trait_ref = ty::TraitRef::new(tcx, sized_def_id, [ty]); // Preferable to put this obligation first, since we report better errors for sized ambiguity. - self.predicates.insert( - 0, - ( - ty::Binder::dummy(ty::Clause::Trait(trait_ref.without_const().to_predicate(tcx))), - span, - ), - ); + self.clauses.insert(0, (trait_ref.to_predicate(tcx), span)); } - pub fn predicates(&self) -> impl Iterator<Item = (Binder<'tcx, ty::Clause<'tcx>>, Span)> + '_ { - self.predicates.iter().cloned() + pub fn clauses(&self) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ { + self.clauses.iter().cloned() } } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index c09734d6e69..a7e81f41c69 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -440,7 +440,7 @@ fn check_opaque_meets_bounds<'tcx>( // Defining use functions may have more bounds than the opaque type, which is ok, as long as the // hidden type is well formed even without those bounds. let predicate = - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(hidden_ty.into()))); + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(hidden_ty.into()))); ocx.register_obligation(Obligation::new(tcx, misc_cause, param_env, predicate)); // Check that all obligations are satisfied by the implementation's @@ -563,8 +563,8 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { check_union(tcx, id.owner_id.def_id); } DefKind::OpaqueTy => { - let opaque = tcx.hir().expect_item(id.owner_id.def_id).expect_opaque_ty(); - if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = opaque.origin + let origin = tcx.opaque_type_origin(id.owner_id.def_id); + if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin && let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id) && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() { diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 838b212ef87..b2ba566f60c 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -321,7 +321,7 @@ fn compare_method_predicate_entailment<'tcx>( infcx.tcx, ObligationCause::dummy(), param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed( + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( unnormalized_impl_fty.into(), ))), )); diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index c9e74896ac0..596c5518086 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -304,7 +304,7 @@ fn bounds_from_generic_predicates<'tcx>( debug!("predicate {:?}", predicate); let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => { let entry = types.entry(trait_predicate.self_ty()).or_default(); let def_id = trait_predicate.def_id(); if Some(def_id) != tcx.lang_items().sized_trait() { @@ -313,7 +313,7 @@ fn bounds_from_generic_predicates<'tcx>( entry.push(trait_predicate.def_id()); } } - ty::PredicateKind::Clause(ty::Clause::Projection(projection_pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(projection_pred)) => { projections.push(bound_predicate.rebind(projection_pred)); } _ => {} @@ -403,7 +403,30 @@ fn fn_sig_suggestion<'tcx>( .flatten() .collect::<Vec<String>>() .join(", "); - let output = sig.output(); + let mut output = sig.output(); + + let asyncness = if tcx.asyncness(assoc.def_id).is_async() { + output = if let ty::Alias(_, alias_ty) = *output.kind() { + tcx.explicit_item_bounds(alias_ty.def_id) + .subst_iter_copied(tcx, alias_ty.substs) + .find_map(|(bound, _)| bound.as_projection_clause()?.no_bound_vars()?.term.ty()) + .unwrap_or_else(|| { + span_bug!( + ident.span, + "expected async fn to have `impl Future` output, but it returns {output}" + ) + }) + } else { + span_bug!( + ident.span, + "expected async fn to have `impl Future` output, but it returns {output}" + ) + }; + "async " + } else { + "" + }; + let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() }; let unsafety = sig.unsafety.prefix_str(); @@ -414,7 +437,9 @@ fn fn_sig_suggestion<'tcx>( // lifetimes between the `impl` and the `trait`, but this should be good enough to // fill in a significant portion of the missing code, and other subsequent // suggestions can help the user fix the code. - format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}") + format!( + "{unsafety}{asyncness}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}" + ) } pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> { @@ -443,19 +468,16 @@ fn suggestion_signature<'tcx>( ); match assoc.kind { - ty::AssocKind::Fn => { - // We skip the binder here because the binder would deanonymize all - // late-bound regions, and we don't want method signatures to show up - // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound - // regions just fine, showing `fn(&MyType)`. - fn_sig_suggestion( - tcx, - tcx.fn_sig(assoc.def_id).subst(tcx, substs).skip_binder(), - assoc.ident(tcx), - tcx.predicates_of(assoc.def_id).instantiate_own(tcx, substs), - assoc, - ) - } + ty::AssocKind::Fn => fn_sig_suggestion( + tcx, + tcx.liberate_late_bound_regions( + assoc.def_id, + tcx.fn_sig(assoc.def_id).subst(tcx, substs), + ), + assoc.ident(tcx), + tcx.predicates_of(assoc.def_id).instantiate_own(tcx, substs), + assoc, + ), ty::AssocKind::Type => { let (generics, where_clauses) = bounds_from_generic_predicates( tcx, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 73a7ba005b3..744eb036933 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -81,7 +81,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { self.tcx(), cause, param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(arg))), + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg))), )); } } @@ -419,10 +419,9 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe let mut unsatisfied_bounds: Vec<_> = required_bounds .into_iter() .filter(|clause| match clause.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate( - a, - b, - ))) => !region_known_to_outlive( + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives( + ty::OutlivesPredicate(a, b), + )) => !region_known_to_outlive( tcx, gat_def_id.def_id, param_env, @@ -430,7 +429,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe a, b, ), - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( a, b, ))) => !ty_known_to_outlive( @@ -574,7 +573,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( ); // The predicate we expect to see. (In our example, // `Self: 'me`.) - let clause = ty::PredicateKind::Clause(ty::Clause::TypeOutlives( + let clause = ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives( ty::OutlivesPredicate(ty_param, region_param), )); let clause = tcx.mk_predicate(ty::Binder::dummy(clause)); @@ -623,7 +622,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( }, ); // The predicate we expect to see. - let clause = ty::PredicateKind::Clause(ty::Clause::RegionOutlives( + let clause = ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives( ty::OutlivesPredicate(region_a_param, region_b_param), )); let clause = tcx.mk_predicate(ty::Binder::dummy(clause)); @@ -1032,7 +1031,7 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b tcx, cause, wfcx.param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable( + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable( ty::Const::from_anon_const(tcx, discr_def_id.expect_local()), ))), )); @@ -1087,7 +1086,7 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt wfcx.infcx, wfcx.param_env, wfcx.body_def_id, - normalized_bound, + normalized_bound.as_predicate(), bound_span, ) }); @@ -1544,8 +1543,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { if let ty::Alias(ty::Opaque, unshifted_opaque_ty) = *ty.kind() && self.seen.insert(unshifted_opaque_ty.def_id) && let Some(opaque_def_id) = unshifted_opaque_ty.def_id.as_local() - && let opaque = tcx.hir().expect_item(opaque_def_id).expect_opaque_ty() - && let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = opaque.origin + && let origin = tcx.opaque_type_origin(opaque_def_id) + && let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = origin && source == self.fn_def_id { let opaque_ty = tcx.fold_regions(unshifted_opaque_ty, |re, _depth| { @@ -1563,7 +1562,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { self.wfcx.infcx, self.wfcx.param_env, self.wfcx.body_def_id, - bound, + bound.as_predicate(), bound_span, )); // Set the debruijn index back to innermost here, since we already eagerly @@ -1876,7 +1875,8 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { // We lower empty bounds like `Vec<dyn Copy>:` as // `WellFormed(Vec<dyn Copy>)`, which will later get checked by // regular WF checking - if let ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) = pred.kind().skip_binder() + if let ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) = + pred.kind().skip_binder() { continue; } diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index a98d8e17153..2441c8667d4 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -571,7 +571,7 @@ fn infringing_fields_error( .or_default() .push(error.obligation.cause.span); } - if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: ty::ImplPolarity::Positive, .. diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 4524b87a418..5097f43607e 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -10,7 +10,6 @@ use rustc_errors::{error_code, struct_span_err}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; -use rustc_span::sym; use rustc_trait_selection::traits; mod builtin; @@ -44,7 +43,7 @@ fn enforce_trait_manually_implementable( let impl_header_span = tcx.def_span(impl_def_id); // Disallow *all* explicit impls of traits marked `#[rustc_deny_explicit_impl]` - if tcx.has_attr(trait_def_id, sym::rustc_deny_explicit_impl) { + if tcx.trait_def(trait_def_id).deny_explicit_impl { let trait_name = tcx.item_name(trait_def_id); let mut err = struct_span_err!( tcx.sess, diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 8b5c1791fc1..eba943e0072 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -991,6 +991,50 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { no_dups.then_some(list) }); + let mut deny_explicit_impl = false; + let mut implement_via_object = true; + if let Some(attr) = tcx.get_attr(def_id, sym::rustc_deny_explicit_impl) { + deny_explicit_impl = true; + let mut seen_attr = false; + for meta in attr.meta_item_list().iter().flatten() { + if let Some(meta) = meta.meta_item() + && meta.name_or_empty() == sym::implement_via_object + && let Some(lit) = meta.name_value_literal() + { + if seen_attr { + tcx.sess.span_err( + meta.span, + "duplicated `implement_via_object` meta item", + ); + } + seen_attr = true; + + match lit.symbol { + kw::True => { + implement_via_object = true; + } + kw::False => { + implement_via_object = false; + } + _ => { + tcx.sess.span_err( + meta.span, + format!("unknown literal passed to `implement_via_object` attribute: {}", lit.symbol), + ); + } + } + } else { + tcx.sess.span_err( + meta.span(), + format!("unknown meta item passed to `rustc_deny_explicit_impl` {:?}", meta), + ); + } + } + if !seen_attr { + tcx.sess.span_err(attr.span, "missing `implement_via_object` meta item"); + } + } + ty::TraitDef { def_id: def_id.to_def_id(), unsafety, @@ -1001,6 +1045,8 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { skip_array_during_method_dispatch, specialization_kind, must_implement_one_of, + implement_via_object, + deny_explicit_impl, } } diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 0479efceaad..958313fee6f 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -3,7 +3,6 @@ use crate::astconv::{AstConv, OnlySelfBounds}; use rustc_hir as hir; use rustc_infer::traits::util; use rustc_middle::ty::subst::InternalSubsts; -use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; @@ -20,7 +19,7 @@ fn associated_type_bounds<'tcx>( assoc_item_def_id: LocalDefId, ast_bounds: &'tcx [hir::GenericBound<'tcx>], span: Span, -) -> &'tcx [(ty::Predicate<'tcx>, Span)] { +) -> &'tcx [(ty::Clause<'tcx>, Span)] { let item_ty = tcx.mk_projection( assoc_item_def_id.to_def_id(), InternalSubsts::identity_for_item(tcx, assoc_item_def_id), @@ -34,23 +33,23 @@ fn associated_type_bounds<'tcx>( let trait_def_id = tcx.local_parent(assoc_item_def_id); let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id); - let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| { - match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(tr)) => tr.self_ty() == item_ty, - ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => { + let bounds_from_parent = trait_predicates + .predicates + .iter() + .copied() + .filter(|(pred, _)| match pred.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr)) => tr.self_ty() == item_ty, + ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) => { proj.projection_ty.self_ty() == item_ty } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(outlives)) => outlives.0 == item_ty, + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => { + outlives.0 == item_ty + } _ => false, - } - }); + }) + .map(|(pred, span)| (pred.expect_clause(), span)); - let all_bounds = tcx.arena.alloc_from_iter( - bounds - .predicates() - .map(|(clause, span)| (clause.to_predicate(tcx), span)) - .chain(bounds_from_parent), - ); + let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent)); debug!( "associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id.to_def_id()), @@ -70,7 +69,7 @@ fn opaque_type_bounds<'tcx>( ast_bounds: &'tcx [hir::GenericBound<'tcx>], item_ty: Ty<'tcx>, span: Span, -) -> &'tcx [(ty::Predicate<'tcx>, Span)] { +) -> &'tcx [(ty::Clause<'tcx>, Span)] { ty::print::with_no_queries!({ let icx = ItemCtxt::new(tcx, opaque_def_id); let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, OnlySelfBounds(false)); @@ -78,16 +77,14 @@ fn opaque_type_bounds<'tcx>( icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span); debug!(?bounds); - tcx.arena.alloc_from_iter( - bounds.predicates().map(|(clause, span)| (clause.to_predicate(tcx), span)), - ) + tcx.arena.alloc_from_iter(bounds.clauses()) }) } pub(super) fn explicit_item_bounds( tcx: TyCtxt<'_>, def_id: LocalDefId, -) -> ty::EarlyBinder<&'_ [(ty::Predicate<'_>, Span)]> { +) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> { match tcx.opt_rpitit_info(def_id.to_def_id()) { // RPITIT's bounds are the same as opaque type bounds, but with // a projection self type. @@ -139,11 +136,8 @@ pub(super) fn explicit_item_bounds( pub(super) fn item_bounds( tcx: TyCtxt<'_>, def_id: DefId, -) -> ty::EarlyBinder<&'_ ty::List<ty::Predicate<'_>>> { +) -> ty::EarlyBinder<&'_ ty::List<ty::Clause<'_>>> { tcx.explicit_item_bounds(def_id).map_bound(|bounds| { - tcx.mk_predicates_from_iter(util::elaborate( - tcx, - bounds.iter().map(|&(bound, _span)| bound), - )) + tcx.mk_clauses_from_iter(util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound))) }) } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index c905db06174..3081f0c386a 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -126,8 +126,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen predicates.extend( icx.astconv() .compute_bounds(tcx.types.self_param, self_bounds, OnlySelfBounds(false)) - .predicates() - .map(|(clause, span)| (clause.to_predicate(tcx), span)), + .clauses() + .map(|(clause, span)| (clause.as_predicate(), span)), ); } @@ -176,9 +176,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen param.span, ); trace!(?bounds); - predicates.extend( - bounds.predicates().map(|(clause, span)| (clause.to_predicate(tcx), span)), - ); + predicates + .extend(bounds.clauses().map(|(clause, span)| (clause.as_predicate(), span))); trace!(?predicates); } GenericParamKind::Const { .. } => { @@ -190,7 +189,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen let ct = tcx.mk_const(param_const, ct_ty); let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( - ty::Clause::ConstArgHasType(ct, ct_ty), + ty::ClauseKind::ConstArgHasType(ct, ct_ty), )) .to_predicate(tcx); predicates.insert((predicate, param.span)); @@ -222,7 +221,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } else { let span = bound_pred.bounded_ty.span; let predicate = ty::Binder::bind_with_vars( - ty::PredicateKind::Clause(ty::Clause::WellFormed(ty.into())), + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty.into())), bound_vars, ); predicates.insert((predicate.to_predicate(tcx), span)); @@ -237,9 +236,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen bound_vars, OnlySelfBounds(false), ); - predicates.extend( - bounds.predicates().map(|(clause, span)| (clause.to_predicate(tcx), span)), - ); + predicates + .extend(bounds.clauses().map(|(clause, span)| (clause.as_predicate(), span))); } hir::WherePredicate::RegionPredicate(region_pred) => { @@ -252,7 +250,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen _ => bug!(), }; let pred = ty::Binder::dummy(ty::PredicateKind::Clause( - ty::Clause::RegionOutlives(ty::OutlivesPredicate(r1, r2)), + ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)), )) .to_predicate(icx.tcx); @@ -320,14 +318,14 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen }, ); predicates.push(( - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::RegionOutlives( + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives( ty::OutlivesPredicate(orig_region, dup_region), ))) .to_predicate(icx.tcx), duplicate.span, )); predicates.push(( - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::RegionOutlives( + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives( ty::OutlivesPredicate(dup_region, orig_region), ))) .to_predicate(icx.tcx), @@ -358,8 +356,10 @@ fn const_evaluatable_predicates_of( if let ty::ConstKind::Unevaluated(_) = ct.kind() { let span = self.tcx.def_span(c.def_id); self.preds.insert(( - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(ct))) - .to_predicate(self.tcx), + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable( + ct, + ))) + .to_predicate(self.tcx), span, )); } @@ -449,11 +449,13 @@ pub(super) fn explicit_predicates_of<'tcx>( .iter() .copied() .filter(|(pred, _)| match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(tr)) => !is_assoc_item_ty(tr.self_ty()), - ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr)) => { + !is_assoc_item_ty(tr.self_ty()) + } + ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) => { !is_assoc_item_ty(proj.projection_ty.self_ty()) } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(outlives)) => { + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => { !is_assoc_item_ty(outlives.0) } _ => true, @@ -496,7 +498,7 @@ pub(super) fn explicit_predicates_of<'tcx>( .predicates .into_iter() .filter(|(pred, _)| { - if let ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, _)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _)) = pred.kind().skip_binder() { match ct.kind() { @@ -665,8 +667,8 @@ pub(super) fn implied_predicates_with_filter( // Combine the two lists to form the complete set of superbounds: let implied_bounds = &*tcx.arena.alloc_from_iter( superbounds - .predicates() - .map(|(clause, span)| (clause.to_predicate(tcx), span)) + .clauses() + .map(|(clause, span)| (clause.as_predicate(), span)) .chain(where_bounds_that_match), ); debug!(?implied_bounds); @@ -677,7 +679,7 @@ pub(super) fn implied_predicates_with_filter( if matches!(filter, PredicateFilter::SelfOnly) { for &(pred, span) in implied_bounds { debug!("superbound: {:?}", pred); - if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) = pred.kind().skip_binder() + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(bound)) = pred.kind().skip_binder() && bound.polarity == ty::ImplPolarity::Positive { tcx.at(span).super_predicates_of(bound.def_id()); @@ -774,7 +776,9 @@ pub(super) fn type_param_predicates( ) .into_iter() .filter(|(predicate, _)| match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) => data.self_ty().is_param(index), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { + data.self_ty().is_param(index) + } _ => false, }), ); @@ -825,7 +829,7 @@ impl<'tcx> ItemCtxt<'tcx> { ); } - bounds.predicates().map(|(clause, span)| (clause.to_predicate(self.tcx), span)).collect() + bounds.clauses().map(|(clause, span)| (clause.as_predicate(), span)).collect() } #[instrument(level = "trace", skip(self))] diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 794812a5ce7..d20f39e9b05 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1761,7 +1761,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| { let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { // The order here needs to match what we would get from `subst_supertrait` let pred_bound_vars = bound_predicate.bound_vars(); let mut all_bound_vars = bound_vars.clone(); diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index 9200c2aecf5..6aecb95b484 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -187,7 +187,7 @@ pub fn setup_constraining_predicates<'tcx>( for j in i..predicates.len() { // Note that we don't have to care about binders here, // as the impl trait ref never contains any late-bound regions. - if let ty::PredicateKind::Clause(ty::Clause::Projection(projection)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(projection)) = predicates[j].0.kind().skip_binder() { // Special case: watch out for some kind of sneaky attempt diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index f2618b3daf1..f1765174d79 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -79,7 +79,7 @@ fn diagnostic_hir_wf_check<'tcx>( self.tcx, cause, self.param_env, - ty::PredicateKind::Clause(ty::Clause::WellFormed(tcx_ty.into())), + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(tcx_ty.into())), )); for error in ocx.select_all_or_error() { diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 201cb94f0b3..97813a291da 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -236,7 +236,7 @@ fn unconstrained_parent_impl_substs<'tcx>( // the functions in `cgp` add the constrained parameters to a list of // unconstrained parameters. for (predicate, _) in impl_generic_predicates.predicates.iter() { - if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) = predicate.kind().skip_binder() { let projection_ty = proj.projection_ty; @@ -438,8 +438,8 @@ fn trait_predicates_eq<'tcx>( let pred2_kind = predicate2.kind().skip_binder(); let (trait_pred1, trait_pred2) = match (pred1_kind, pred2_kind) { ( - ty::PredicateKind::Clause(ty::Clause::Trait(pred1)), - ty::PredicateKind::Clause(ty::Clause::Trait(pred2)), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred1)), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred2)), ) => (pred1, pred2), // Just use plain syntactic equivalence if either of the predicates aren't // trait predicates or have bound vars. @@ -478,7 +478,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc _ if predicate.is_global() => (), // We allow specializing on explicitly marked traits with no associated // items. - ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, constness: _, polarity: _, @@ -498,7 +498,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc .emit(); } } - ty::PredicateKind::Clause(ty::Clause::Projection(ty::ProjectionPredicate { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term, })) => { @@ -509,7 +509,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc ) .emit(); } - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => { // FIXME(min_specialization), FIXME(const_generics): // It probably isn't right to allow _every_ `ConstArgHasType` but I am somewhat unsure // about the actual rules that would be sound. Can't just always error here because otherwise @@ -532,22 +532,22 @@ fn trait_predicate_kind<'tcx>( predicate: ty::Predicate<'tcx>, ) -> Option<TraitSpecializationKind> { match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, constness: _, polarity: _, })) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind), - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(_)) - | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_)) - | ty::PredicateKind::Clause(ty::Clause::Projection(_)) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::Clause(ty::Clause::WellFormed(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) | ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) | ty::PredicateKind::ObjectSafe(_) | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index 79c56490f3c..e63549998d2 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -30,7 +30,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { // process predicates and convert to `RequiredPredicates` entry, see below for &(predicate, span) in predicates.predicates { match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(OutlivesPredicate( ty, reg, ))) => insert_outlives_predicate( @@ -41,10 +41,9 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { &mut required_predicates, ), - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(OutlivesPredicate( - reg1, - reg2, - ))) => insert_outlives_predicate( + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives( + OutlivesPredicate(reg1, reg2), + )) => insert_outlives_predicate( tcx, reg1.into(), reg2, @@ -52,16 +51,16 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { &mut required_predicates, ), - ty::PredicateKind::Clause(ty::Clause::Trait(..)) - | ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => (), diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs index fdbb890ce3d..48624cefe4d 100644 --- a/compiler/rustc_hir_analysis/src/outlives/mod.rs +++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs @@ -3,7 +3,7 @@ use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_middle::query::Providers; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt}; +use rustc_middle::ty::{self, CratePredicatesMap, ToPredicate, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -52,9 +52,9 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clau if tcx.has_attr(item_def_id, sym::rustc_outlives) { let mut pred: Vec<String> = predicates .iter() - .map(|(out_pred, _)| match out_pred { - ty::Clause::RegionOutlives(p) => p.to_string(), - ty::Clause::TypeOutlives(p) => p.to_string(), + .map(|(out_pred, _)| match out_pred.kind().skip_binder() { + ty::ClauseKind::RegionOutlives(p) => p.to_string(), + ty::ClauseKind::TypeOutlives(p) => p.to_string(), err => bug!("unexpected clause {:?}", err), }) .collect(); @@ -104,13 +104,15 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> { |(ty::OutlivesPredicate(kind1, region2), &span)| { match kind1.unpack() { GenericArgKind::Type(ty1) => Some(( - ty::Clause::TypeOutlives(ty::OutlivesPredicate(ty1, *region2)), + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty1, *region2)) + .to_predicate(tcx), span, )), GenericArgKind::Lifetime(region1) => Some(( - ty::Clause::RegionOutlives(ty::OutlivesPredicate( + ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( region1, *region2, - )), + )) + .to_predicate(tcx), span, )), GenericArgKind::Const(_) => { diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 3ebd9e134bf..23d8da88a45 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -162,28 +162,25 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc // which thus mentions `'a` and should thus accept hidden types that borrow 'a // instead of requiring an additional `+ 'a`. match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { + ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref: ty::TraitRef { def_id: _, substs, .. }, constness: _, polarity: _, - })) => { + }) => { for subst in &substs[1..] { subst.visit_with(&mut collector); } } - ty::PredicateKind::Clause(ty::Clause::Projection(ty::ProjectionPredicate { + ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty: ty::AliasTy { substs, .. }, term, - })) => { + }) => { for subst in &substs[1..] { subst.visit_with(&mut collector); } term.visit_with(&mut collector); } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( - _, - region, - ))) => { + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(_, region)) => { region.visit_with(&mut collector); } _ => { diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 444ff90595c..c7fa27da1ac 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -536,31 +536,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } for ty in [first_ty, second_ty] { - for (pred, _) in self + for (clause, _) in self .tcx .explicit_item_bounds(rpit_def_id) .subst_iter_copied(self.tcx, substs) { - let pred = pred.kind().rebind(match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => { + let pred = clause.kind().rebind(match clause.kind().skip_binder() { + ty::ClauseKind::Trait(trait_pred) => { // FIXME(rpitit): This will need to be fixed when we move to associated types assert!(matches!( *trait_pred.trait_ref.self_ty().kind(), ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. }) if def_id == rpit_def_id && substs == alias_substs )); - ty::PredicateKind::Clause(ty::Clause::Trait( - trait_pred.with_self_ty(self.tcx, ty), - )) + ty::ClauseKind::Trait(trait_pred.with_self_ty(self.tcx, ty)) } - ty::PredicateKind::Clause(ty::Clause::Projection(mut proj_pred)) => { + ty::ClauseKind::Projection(mut proj_pred) => { assert!(matches!( *proj_pred.projection_ty.self_ty().kind(), ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. }) if def_id == rpit_def_id && substs == alias_substs )); proj_pred = proj_pred.with_self_ty(self.tcx, ty); - ty::PredicateKind::Clause(ty::Clause::Projection(proj_pred)) + ty::ClauseKind::Projection(proj_pred) } _ => continue, }); diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 69ccbf0b58f..0a1b639af51 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -92,10 +92,7 @@ pub(super) fn check_fn<'a, 'tcx>( fcx.check_pat_top(¶m.pat, param_ty, ty_span, None); // Check that argument is Sized. - // The check for a non-trivial pattern is a hack to avoid duplicate warnings - // for simple cases like `fn foo(x: Trait)`, - // where we would error once on the parameter as a whole, and once on the binding `x`. - if param.pat.simple_ident().is_none() && !params_can_be_unsized { + if !params_can_be_unsized { fcx.require_type_is_sized( param_ty, param.pat.span, diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index dce426ca2db..c64b64e925a 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -174,7 +174,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self .deduce_closure_signature_from_predicates( expected_ty, - self.tcx.explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs), + self.tcx + .explicit_item_bounds(def_id) + .subst_iter_copied(self.tcx, substs) + .map(|(c, s)| (c.as_predicate(), s)), ), ty::Dynamic(ref object_type, ..) => { let sig = object_type.projection_bounds().find_map(|pb| { @@ -222,7 +225,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Given a Projection predicate, we can potentially infer // the complete signature. if expected_sig.is_none() - && let ty::PredicateKind::Clause(ty::Clause::Projection(proj_predicate)) = bound_predicate.skip_binder() + && let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj_predicate)) = bound_predicate.skip_binder() { let inferred_sig = self.normalize( span, @@ -258,10 +261,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // like `F : Fn<A>`. Note that due to subtyping we could encounter // many viable options, so pick the most restrictive. let trait_def_id = match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => { Some(data.projection_ty.trait_def_id(self.tcx)) } - ty::PredicateKind::Clause(ty::Clause::Trait(data)) => Some(data.def_id()), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => Some(data.def_id()), _ => None, }; if let Some(closure_kind) = @@ -695,7 +698,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // where R is the return type we are expecting. This type `T` // will be our output. let bound_predicate = predicate.kind(); - if let ty::PredicateKind::Clause(ty::Clause::Projection(proj_predicate)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj_predicate)) = bound_predicate.skip_binder() { self.deduce_future_output_from_projection( @@ -717,13 +720,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .tcx .explicit_item_bounds(def_id) .subst_iter_copied(self.tcx, substs) - .find_map(|(p, s)| get_future_output(p, s))?, + .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?, ty::Error(_) => return None, ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => self .tcx .explicit_item_bounds(proj.def_id) .subst_iter_copied(self.tcx, proj.substs) - .find_map(|(p, s)| get_future_output(p, s))?, + .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?, _ => span_bug!( self.tcx.def_span(expr_def_id), "async fn generator return type not an inference variable: {ret_ty}" diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 79157eae7ed..c0c839b1f18 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -631,7 +631,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { debug!("coerce_unsized resolve step: {:?}", obligation); let bound_predicate = obligation.predicate.kind(); let trait_pred = match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) if traits.contains(&trait_pred.def_id()) => { if unsize_did == trait_pred.def_id() { @@ -767,7 +767,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.tcx, self.cause.clone(), self.param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::TypeOutlives( + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives( ty::OutlivesPredicate(a, b_region), ))), ), diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index b62f689ec6b..9ce03060e0f 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -370,13 +370,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Fudge the receiver, so we can do new inference on it. let possible_rcvr_ty = possible_rcvr_ty.fold_with(&mut fudger); let method = self - .lookup_method( + .lookup_method_for_diagnostic( possible_rcvr_ty, segment, DUMMY_SP, call_expr, binding, - args, ) .ok()?; // Unify the method signature with our incompatible arg, to @@ -435,14 +434,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else { continue; }; let rcvr_ty = rcvr_ty.fold_with(&mut fudger); let Ok(method) = - self.lookup_method(rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr, args) + self.lookup_method_for_diagnostic(rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr) else { continue; }; let ideal_rcvr_ty = rcvr_ty.fold_with(&mut fudger); let ideal_method = self - .lookup_method(ideal_rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr, args) + .lookup_method_for_diagnostic(ideal_rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr) .ok() .and_then(|method| { let _ = self.at(&ObligationCause::dummy(), self.param_env) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 3f6847be91b..e250e68a7f1 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2983,7 +2983,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { for error in errors { match error.obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) if self.tcx.is_diagnostic_item(sym::SliceIndex, predicate.trait_ref.def_id) => { } _ => continue, diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index e14e8ac2ce0..82d9f03b145 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -443,7 +443,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { if matches!((lhs, wild, rhs), (&[], Some(_), &[])) // Arrays have a statically known size, so // there is no need to read their length - || discr_place.place.base_ty.is_array() + || place.place.ty().peel_refs().is_array() { } else { needs_to_be_read = true; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 34f98f4310e..b44c51ba945 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -483,7 +483,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx, cause, self.param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(arg))), + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg))), )); } @@ -647,7 +647,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.fulfillment_cx.borrow().pending_obligations().into_iter().filter_map( move |obligation| match &obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(data)) + ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) if self.self_type_matches_expected_vid( data.projection_ty.self_ty(), ty_var_root, @@ -655,23 +655,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { Some(obligation) } - ty::PredicateKind::Clause(ty::Clause::Trait(data)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) if self.self_type_matches_expected_vid(data.self_ty(), ty_var_root) => { Some(obligation) } - ty::PredicateKind::Clause(ty::Clause::Trait(..)) - | ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) // N.B., this predicate is created by breaking down a // `ClosureType: FnFoo()` predicate, where @@ -692,7 +692,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let sized_did = self.tcx.lang_items().sized_trait(); self.obligations_for_self_ty(self_ty).any(|obligation| { match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { Some(data.def_id()) == sized_did } _ => false, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index 2135643cbeb..880437023c8 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -25,14 +25,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let generics = self.tcx.generics_of(def_id); let predicate_substs = match unsubstituted_pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs.to_vec(), - ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { + pred.trait_ref.substs.to_vec() + } + ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { pred.projection_ty.substs.to_vec() } - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(arg, ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(arg, ty)) => { vec![ty.into(), arg.into()] } - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(e)) => vec![e.into()], + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(e)) => vec![e.into()], _ => return false, }; @@ -514,7 +516,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { impl_predicates.predicates[impl_predicate_index].0.kind().skip_binder(); match relevant_broken_predicate { - ty::PredicateKind::Clause(ty::Clause::Trait(broken_trait)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(broken_trait)) => { // ... self.blame_specific_part_of_expr_corresponding_to_generic_param( broken_trait.trait_ref.self_ty().into(), diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs index d45e3d395e4..7aadb95d939 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs @@ -1,7 +1,7 @@ -use std::cmp; - +use core::cmp::Ordering; use rustc_index::IndexVec; use rustc_middle::ty::error::TypeError; +use std::cmp; rustc_index::newtype_index! { #[debug_format = "ExpectedIdx({})"] @@ -34,14 +34,14 @@ enum Issue { Permutation(Vec<Option<usize>>), } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Eq, PartialEq)] pub(crate) enum Compatibility<'tcx> { Compatible, Incompatible(Option<TypeError<'tcx>>), } /// Similar to `Issue`, but contains some extra information -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] pub(crate) enum Error<'tcx> { /// The provided argument is the invalid type for the expected input Invalid(ProvidedIdx, ExpectedIdx, Compatibility<'tcx>), @@ -55,6 +55,34 @@ pub(crate) enum Error<'tcx> { Permutation(Vec<(ExpectedIdx, ProvidedIdx)>), } +impl Ord for Error<'_> { + fn cmp(&self, other: &Self) -> Ordering { + let key = |error: &Error<'_>| -> usize { + match error { + Error::Invalid(..) => 0, + Error::Extra(_) => 1, + Error::Missing(_) => 2, + Error::Swap(..) => 3, + Error::Permutation(..) => 4, + } + }; + match (self, other) { + (Error::Invalid(a, _, _), Error::Invalid(b, _, _)) => a.cmp(b), + (Error::Extra(a), Error::Extra(b)) => a.cmp(b), + (Error::Missing(a), Error::Missing(b)) => a.cmp(b), + (Error::Swap(a, b, ..), Error::Swap(c, d, ..)) => a.cmp(c).then(b.cmp(d)), + (Error::Permutation(a), Error::Permutation(b)) => a.cmp(b), + _ => key(self).cmp(&key(other)), + } + } +} + +impl PartialOrd for Error<'_> { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + pub(crate) struct ArgMatrix<'tcx> { /// Maps the indices in the `compatibility_matrix` rows to the indices of /// the *user provided* inputs @@ -177,7 +205,7 @@ impl<'tcx> ArgMatrix<'tcx> { // If an argument is unsatisfied, and the input in its position is useless // then the most likely explanation is that we just got the types wrong (true, true, true, true) => return Some(Issue::Invalid(i)), - // Otherwise, if an input is useless, then indicate that this is an extra argument + // Otherwise, if an input is useless then indicate that this is an extra input (true, _, true, _) => return Some(Issue::Extra(i)), // Otherwise, if an argument is unsatisfiable, indicate that it's missing (_, true, _, true) => return Some(Issue::Missing(i)), @@ -376,6 +404,9 @@ impl<'tcx> ArgMatrix<'tcx> { }; } + // sort errors with same type by the order they appear in the source + // so that suggestion will be handled properly, see #112507 + errors.sort(); return (errors, matched_inputs); } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index bf8ad5faac4..f294ff0051d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1948,7 +1948,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // do that, so it's OK. for (predicate, span) in instantiated { - if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = predicate.kind().skip_binder() + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = predicate.kind().skip_binder() && pred.self_ty().peel_refs() == callee_ty && self.tcx.is_fn_trait(pred.def_id()) { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 630878bbf0c..d311ebe8c32 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -226,7 +226,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { predicates: tcx.arena.alloc_from_iter( self.param_env.caller_bounds().iter().filter_map(|predicate| { match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) if data.self_ty().is_param(index) => { // HACK(eddyb) should get the original `Span`. diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index fb28233bfb1..fdbb153ec7d 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -577,7 +577,7 @@ fn check_must_not_suspend_ty<'tcx>( let mut has_emitted = false; for &(predicate, _) in fcx.tcx.explicit_item_bounds(def).skip_binder() { // We only look at the `DefId`, so it is safe to skip the binder here. - if let ty::PredicateKind::Clause(ty::Clause::Trait(ref poly_trait_predicate)) = + if let ty::ClauseKind::Trait(ref poly_trait_predicate) = predicate.kind().skip_binder() { let def_id = poly_trait_predicate.trait_ref.def_id; diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs index aa4f90b4ad8..c193d761804 100644 --- a/compiler/rustc_hir_typeck/src/inherited.rs +++ b/compiler/rustc_hir_typeck/src/inherited.rs @@ -129,7 +129,7 @@ impl<'tcx> Inherited<'tcx> { let infer_var_info = &mut self.infer_var_info.borrow_mut(); // (*) binder skipped - if let ty::PredicateKind::Clause(ty::Clause::Trait(tpred)) = obligation.predicate.kind().skip_binder() + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(tpred)) = obligation.predicate.kind().skip_binder() && let Some(ty) = self.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| self.root_var(t)) && self.tcx.lang_items().sized_trait().is_some_and(|st| st != tpred.trait_ref.def_id) { @@ -143,7 +143,7 @@ impl<'tcx> Inherited<'tcx> { .kind() .rebind( // (*) binder moved here - ty::PredicateKind::Clause(ty::Clause::Trait(tpred.with_self_ty(self.tcx, new_self_ty))) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(tpred.with_self_ty(self.tcx, new_self_ty))) ), ); // Don't report overflow errors. Otherwise equivalent to may_hold. @@ -152,7 +152,7 @@ impl<'tcx> Inherited<'tcx> { } } - if let ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) = obligation.predicate.kind().skip_binder() { // If the projection predicate (Foo::Bar == X) has X as a non-TyVid, diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 98529b66602..279ff849e3d 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -26,6 +26,7 @@ struct ConfirmContext<'a, 'tcx> { span: Span, self_expr: &'tcx hir::Expr<'tcx>, call_expr: &'tcx hir::Expr<'tcx>, + skip_record_for_diagnostics: bool, } impl<'a, 'tcx> Deref for ConfirmContext<'a, 'tcx> { @@ -59,6 +60,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr); confirm_cx.confirm(unadjusted_self_ty, pick, segment) } + + pub fn confirm_method_for_diagnostic( + &self, + span: Span, + self_expr: &'tcx hir::Expr<'tcx>, + call_expr: &'tcx hir::Expr<'tcx>, + unadjusted_self_ty: Ty<'tcx>, + pick: &probe::Pick<'tcx>, + segment: &hir::PathSegment<'_>, + ) -> ConfirmResult<'tcx> { + let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr); + confirm_cx.skip_record_for_diagnostics = true; + confirm_cx.confirm(unadjusted_self_ty, pick, segment) + } } impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { @@ -68,7 +83,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self_expr: &'tcx hir::Expr<'tcx>, call_expr: &'tcx hir::Expr<'tcx>, ) -> ConfirmContext<'a, 'tcx> { - ConfirmContext { fcx, span, self_expr, call_expr } + ConfirmContext { fcx, span, self_expr, call_expr, skip_record_for_diagnostics: false } } fn confirm( @@ -219,7 +234,9 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.register_predicates(autoderef.into_obligations()); // Write out the final adjustments. - self.apply_adjustments(self.self_expr, adjustments); + if !self.skip_record_for_diagnostics { + self.apply_adjustments(self.self_expr, adjustments); + } target } @@ -453,7 +470,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { }); debug!("instantiate_method_substs: user_type_annotation={:?}", user_type_annotation); - self.fcx.write_user_type_annotation(self.call_expr.hir_id, user_type_annotation); + + if !self.skip_record_for_diagnostics { + self.fcx.write_user_type_annotation(self.call_expr.hir_id, user_type_annotation); + } } self.normalize(self.span, substs) @@ -586,7 +606,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { traits::elaborate(self.tcx, predicates.predicates.iter().copied()) // We don't care about regions here. .filter_map(|pred| match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) if trait_pred.def_id() == sized_def_id => { let span = predicates diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index cca97d10517..ebd7b3123eb 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -254,6 +254,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(result.callee) } + pub fn lookup_method_for_diagnostic( + &self, + self_ty: Ty<'tcx>, + segment: &hir::PathSegment<'_>, + span: Span, + call_expr: &'tcx hir::Expr<'tcx>, + self_expr: &'tcx hir::Expr<'tcx>, + ) -> Result<MethodCallee<'tcx>, MethodError<'tcx>> { + let pick = self.lookup_probe_for_diagnostic( + segment.ident, + self_ty, + call_expr, + ProbeScope::TraitsInScope, + None, + )?; + + Ok(self + .confirm_method_for_diagnostic(span, self_expr, call_expr, self_ty, &pick, segment) + .callee) + } + #[instrument(level = "debug", skip(self, call_expr))] pub fn lookup_probe( &self, @@ -452,7 +473,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx, obligation.cause, self.param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(method_ty.into()))), + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( + method_ty.into(), + ))), )); let callee = MethodCallee { def_id, substs, sig: fn_sig }; diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 91347c01327..762176ecfc7 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -12,6 +12,7 @@ use rustc_hir::def::DefKind; use rustc_hir_analysis::autoderef::{self, Autoderef}; use rustc_infer::infer::canonical::OriginalQueryValues; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; +use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; use rustc_middle::middle::stability; @@ -448,15 +449,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } } else { - // Encountered a real ambiguity, so abort the lookup. If `ty` is not - // an `Err`, report the right "type annotations needed" error pointing - // to it. + // Ended up encountering a type variable when doing autoderef, + // but it may not be a type variable after processing obligations + // in our local `FnCtxt`, so don't call `structurally_resolved_type`. let ty = &bad_ty.ty; let ty = self .probe_instantiate_query_response(span, &orig_values, ty) .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty)); - let ty = self.structurally_resolved_type(span, ty.value); - assert!(matches!(ty.kind(), ty::Error(_))); + let ty = self.resolve_vars_if_possible(ty.value); + let guar = match *ty.kind() { + ty::Infer(ty::TyVar(_)) => self + .err_ctxt() + .emit_inference_failure_err(self.body_id, span, ty.into(), E0282, true) + .emit(), + ty::Error(guar) => guar, + _ => bug!("unexpected bad final type in method autoderef"), + }; + self.demand_eqtype(span, ty, self.tcx.ty_error(guar)); return Err(MethodError::NoMatch(NoMatchData { static_candidates: Vec::new(), unsatisfied_predicates: Vec::new(), @@ -825,7 +834,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| { let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => { match *trait_predicate.trait_ref.self_ty().kind() { ty::Param(p) if p == param_ty => { Some(bound_predicate.rebind(trait_predicate.trait_ref)) @@ -834,15 +843,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } ty::PredicateKind::Subtype(..) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::AliasRelate(..) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 66e771b794a..67fb7c1d48c 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -542,7 +542,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut unimplemented_traits = FxHashMap::default(); let mut unimplemented_traits_only = true; for (predicate, _parent_pred, cause) in unsatisfied_predicates { - if let (ty::PredicateKind::Clause(ty::Clause::Trait(p)), Some(cause)) = + if let (ty::PredicateKind::Clause(ty::ClauseKind::Trait(p)), Some(cause)) = (predicate.kind().skip_binder(), cause.as_ref()) { if p.trait_ref.self_ty() != rcvr_ty { @@ -569,7 +569,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // because of some non-Clone item being iterated over. for (predicate, _parent_pred, _cause) in unsatisfied_predicates { match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(p)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(p)) if unimplemented_traits.contains_key(&p.trait_ref.def_id) => {} _ => { unimplemented_traits_only = false; @@ -581,7 +581,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut collect_type_param_suggestions = |self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| { // We don't care about regions here, so it's fine to skip the binder here. - if let (ty::Param(_), ty::PredicateKind::Clause(ty::Clause::Trait(p))) = + if let (ty::Param(_), ty::PredicateKind::Clause(ty::ClauseKind::Trait(p))) = (self_ty.kind(), parent_pred.kind().skip_binder()) { let hir = self.tcx.hir(); @@ -641,7 +641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut format_pred = |pred: ty::Predicate<'tcx>| { let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { let pred = bound_predicate.rebind(pred); // `<Foo as Iterator>::Item = String`. let projection_ty = pred.skip_binder().projection_ty; @@ -665,7 +665,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { bound_span_label(projection_ty.self_ty(), &obligation, &quiet); Some((obligation, projection_ty.self_ty())) } - ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_ref)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(poly_trait_ref)) => { let p = poly_trait_ref.trait_ref; let self_ty = p.self_ty(); let path = p.print_only_trait_path(); @@ -698,7 +698,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Don't point out the span of `WellFormed` predicates. if !matches!( p.kind().skip_binder(), - ty::PredicateKind::Clause(ty::Clause::Projection(..) | ty::Clause::Trait(..)) + ty::PredicateKind::Clause( + ty::ClauseKind::Projection(..) | ty::ClauseKind::Trait(..) + ) ) { continue; }; @@ -740,7 +742,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let sized_pred = unsatisfied_predicates.iter().any(|(pred, _, _)| { match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { Some(pred.def_id()) == self.tcx.lang_items().sized_trait() && pred.polarity == ty::ImplPolarity::Positive } @@ -2012,16 +2014,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let all_local_types_needing_impls = errors.iter().all(|e| match e.obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => match pred.self_ty().kind() { - ty::Adt(def, _) => def.did().is_local(), - _ => false, - }, + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { + match pred.self_ty().kind() { + ty::Adt(def, _) => def.did().is_local(), + _ => false, + } + } _ => false, }); let mut preds: Vec<_> = errors .iter() .filter_map(|e| match e.obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => Some(pred), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => Some(pred), _ => None, }) .collect(); @@ -2092,7 +2096,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut derives = Vec::<(String, Span, Symbol)>::new(); let mut traits = Vec::new(); for (pred, _, _) in unsatisfied_predicates { - let Some(ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred))) = + let Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred))) = pred.kind().no_bound_vars() else { continue @@ -2527,10 +2531,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match p.kind().skip_binder() { // Hide traits if they are present in predicates as they can be fixed without // having to implement them. - ty::PredicateKind::Clause(ty::Clause::Trait(t)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => { t.def_id() == info.def_id } - ty::PredicateKind::Clause(ty::Clause::Projection(p)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => { p.projection_ty.def_id == info.def_id } _ => false, diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index cbe77e7b16d..f9cd01fd80d 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -198,7 +198,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { let (name, mut auto) = self.auto_labels(item_id, attr); let except = self.except(attr); let loaded_from_disk = self.loaded_from_disk(attr); - for e in except.items().map(|x| x.as_str()).into_sorted_stable_ord() { + for e in except.items().into_sorted_stable_ord() { if !auto.remove(e) { self.tcx.sess.emit_fatal(errors::AssertionAuto { span: attr.span, name, e }); } @@ -377,17 +377,15 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { continue; }; self.checked_attrs.insert(attr.id); - for label in assertion.clean.items().map(|x| x.as_str()).into_sorted_stable_ord() { + for label in assertion.clean.items().into_sorted_stable_ord() { let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap(); self.assert_clean(item_span, dep_node); } - for label in assertion.dirty.items().map(|x| x.as_str()).into_sorted_stable_ord() { + for label in assertion.dirty.items().into_sorted_stable_ord() { let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap(); self.assert_dirty(item_span, dep_node); } - for label in - assertion.loaded_from_disk.items().map(|x| x.as_str()).into_sorted_stable_ord() - { + for label in assertion.loaded_from_disk.items().into_sorted_stable_ord() { let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap(); self.assert_loaded_from_disk(item_span, dep_node); } diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 243057b99bc..7708deecec7 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -855,12 +855,11 @@ fn all_except_most_recent( let most_recent = deletion_candidates.items().map(|(&(timestamp, _), _)| timestamp).max(); if let Some(most_recent) = most_recent { - UnordMap::from( - deletion_candidates - .into_items() - .filter(|&((timestamp, _), _)| timestamp != most_recent) - .map(|((_, path), lock)| (path, lock)), - ) + deletion_candidates + .into_items() + .filter(|&((timestamp, _), _)| timestamp != most_recent) + .map(|((_, path), lock)| (path, lock)) + .collect() } else { UnordMap::default() } diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 2cf8d8c702d..630014e2380 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -584,12 +584,12 @@ impl<'tcx> InferCtxt<'tcx> { let ty::OutlivesPredicate(k1, r2) = predicate; let atom = match k1.unpack() { - GenericArgKind::Lifetime(r1) => { - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate(r1, r2))) - } - GenericArgKind::Type(t1) => { - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(t1, r2))) - } + GenericArgKind::Lifetime(r1) => ty::PredicateKind::Clause( + ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)), + ), + GenericArgKind::Type(t1) => ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives( + ty::OutlivesPredicate(t1, r2), + )), GenericArgKind::Const(..) => { // Consts cannot outlive one another, so we don't expect to // encounter this branch. @@ -739,9 +739,9 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { self.obligations.push(Obligation { cause: self.cause.clone(), param_env: self.param_env, - predicate: ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::RegionOutlives( - ty::OutlivesPredicate(sup, sub), - ))) + predicate: ty::Binder::dummy(ty::PredicateKind::Clause( + ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(sup, sub)), + )) .to_predicate(self.infcx.tcx), recursion_depth: 0, }); diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 152c56572b6..fc6ff01c00c 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -124,13 +124,10 @@ impl<'tcx> InferCtxt<'tcx> { } // During coherence, opaque types should be treated as *possibly* - // equal to each other, even if their generic params differ, as - // they could resolve to the same hidden type, even for different - // generic params. - ( - &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), - &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), - ) if self.intercrate && a_def_id == b_def_id => { + // equal to any other type (except for possibly itself). This is an + // extremely heavy hammer, but can be relaxed in a fowards-compatible + // way later. + (&ty::Alias(ty::Opaque, _), _) | (_, &ty::Alias(ty::Opaque, _)) if self.intercrate => { relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]); Ok(a) } @@ -417,7 +414,9 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { self.tcx(), self.trace.cause.clone(), self.param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(b_ty.into()))), + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( + b_ty.into(), + ))), )); } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index fc1f90fdc13..15213c4b023 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -408,7 +408,7 @@ impl<'tcx> InferCtxt<'tcx> { predicate .kind() .map_bound(|kind| match kind { - ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate)) + ty::ClauseKind::Projection(projection_predicate) if projection_predicate.projection_ty.def_id == item_def_id => { projection_predicate.term.ty() diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index a723dc3f079..2a32f0b5047 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -260,7 +260,8 @@ impl<T> Trait<T> for X { (ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if alias.def_id.is_local() && matches!(tcx.def_kind(body_owner_def_id), DefKind::AssocFn | DefKind::AssocConst) => { if tcx.is_type_alias_impl_trait(alias.def_id) { if !tcx.opaque_types_defined_by(body_owner_def_id.expect_local()).contains(&alias.def_id.expect_local()) { - diag.span_note(tcx.def_span(body_owner_def_id), "\ + let sp = tcx.def_ident_span(body_owner_def_id).unwrap_or_else(|| tcx.def_span(body_owner_def_id)); + diag.span_note(sp, "\ this item must have the opaque type in its signature \ in order to be able to register hidden types"); } diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 6b8293f90f1..3098b8bc2f9 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -378,7 +378,7 @@ impl<'tcx> InferCtxt<'tcx> { DefiningAnchor::Bind(bind) => bind, }; - let origin = self.opaque_type_origin_unchecked(def_id); + let origin = self.tcx.opaque_type_origin(def_id); let in_definition_scope = match origin { // Async `impl Trait` hir::OpaqueTyOrigin::AsyncFn(parent) => parent == parent_def_id, @@ -395,13 +395,6 @@ impl<'tcx> InferCtxt<'tcx> { }; in_definition_scope.then_some(origin) } - - /// Returns the origin of the opaque type `def_id` even if we are not in its - /// defining scope. - #[instrument(skip(self), level = "trace", ret)] - fn opaque_type_origin_unchecked(&self, def_id: LocalDefId) -> OpaqueTyOrigin { - self.tcx.hir().expect_item(def_id).expect_opaque_ty().origin - } } /// Visitor that requires that (almost) all regions in the type visited outlive @@ -536,7 +529,8 @@ impl<'tcx> InferCtxt<'tcx> { )?; self.add_item_bounds_for_hidden_type( - opaque_type_key, + opaque_type_key.def_id.to_def_id(), + opaque_type_key.substs, cause, param_env, hidden_ty, @@ -598,7 +592,8 @@ impl<'tcx> InferCtxt<'tcx> { pub fn add_item_bounds_for_hidden_type( &self, - OpaqueTypeKey { def_id, substs }: OpaqueTypeKey<'tcx>, + def_id: DefId, + substs: ty::SubstsRef<'tcx>, cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, hidden_ty: Ty<'tcx>, @@ -631,7 +626,7 @@ impl<'tcx> InferCtxt<'tcx> { // Replace all other mentions of the same opaque type with the hidden type, // as the bounds must hold on the hidden type after all. ty::Alias(ty::Opaque, ty::AliasTy { def_id: def_id2, substs: substs2, .. }) - if def_id.to_def_id() == def_id2 && substs == substs2 => + if def_id == def_id2 && substs == substs2 => { hidden_ty } @@ -640,16 +635,14 @@ impl<'tcx> InferCtxt<'tcx> { ty::Alias( ty::Projection, ty::AliasTy { def_id: def_id2, substs: substs2, .. }, - ) if def_id.to_def_id() == def_id2 && substs == substs2 => hidden_ty, + ) if def_id == def_id2 && substs == substs2 => hidden_ty, _ => ty, }, lt_op: |lt| lt, ct_op: |ct| ct, }); - if let ty::PredicateKind::Clause(ty::Clause::Projection(projection)) = - predicate.kind().skip_binder() - { + if let ty::ClauseKind::Projection(projection) = predicate.kind().skip_binder() { if projection.term.references_error() { // No point on adding any obligations since there's a type error involved. obligations.clear(); diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index c1f0b9253a5..d926f7f7cbd 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -23,21 +23,21 @@ pub fn explicit_outlives_bounds<'tcx>( .map(ty::Predicate::kind) .filter_map(ty::Binder::no_bound_vars) .filter_map(move |kind| match kind { - ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::Clause(ty::Clause::Trait(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::Subtype(..) - | ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( r_a, r_b, ))) => Some(OutlivesBound::RegionSubRegion(r_b, r_a)), diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 59ae2ce6c60..871171f9447 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -296,7 +296,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { trace!("{:#?}", bounds.skip_binder()); bounds .subst_iter(tcx, alias_ty.substs) - .filter_map(|p| p.to_opt_type_outlives()) + .filter_map(|p| p.as_type_outlives_clause()) .filter_map(|p| p.no_bound_vars()) .map(|OutlivesPredicate(_, r)| r) } diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs index 4f8c9188cf8..75455533181 100644 --- a/compiler/rustc_infer/src/infer/projection.rs +++ b/compiler/rustc_infer/src/infer/projection.rs @@ -27,7 +27,7 @@ impl<'tcx> InferCtxt<'tcx> { // // The new solver correctly handles projection equality so this hack // is not necessary. if re-enabled it should emit `PredicateKind::AliasRelate` - // not `PredicateKind::Clause(Clause::Projection(..))` as in the new solver + // not `PredicateKind::Clause(ClauseKind::Projection(..))` as in the new solver // `Projection` is used as `normalizes-to` which will fail for `<T as Trait>::Assoc eq ?0`. return projection_ty.to_ty(self.tcx); } else { @@ -36,9 +36,10 @@ impl<'tcx> InferCtxt<'tcx> { kind: TypeVariableOriginKind::NormalizeProjectionType, span: self.tcx.def_span(def_id), }); - let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Projection( - ty::ProjectionPredicate { projection_ty, term: ty_var.into() }, - ))); + let projection = + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Projection( + ty::ProjectionPredicate { projection_ty, term: ty_var.into() }, + ))); let obligation = Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection); obligations.push(obligation); diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 8ce8b4e2024..6da490a90ee 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -79,8 +79,8 @@ impl<'tcx> PredicateObligation<'tcx> { pub fn without_const(mut self, tcx: TyCtxt<'tcx>) -> PredicateObligation<'tcx> { self.param_env = self.param_env.without_const(); - if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = self.predicate.kind().skip_binder() && trait_pred.is_const_if_const() { - self.predicate = tcx.mk_predicate(self.predicate.kind().map_bound(|_| ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred.without_const())))); + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) = self.predicate.kind().skip_binder() && trait_pred.is_const_if_const() { + self.predicate = tcx.mk_predicate(self.predicate.kind().map_bound(|_| ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred.without_const())))); } self } diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 5622062ef7e..26919872952 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -167,6 +167,46 @@ impl<'tcx> Elaboratable<'tcx> for (ty::Predicate<'tcx>, Span) { } } +impl<'tcx> Elaboratable<'tcx> for (ty::Clause<'tcx>, Span) { + fn predicate(&self) -> ty::Predicate<'tcx> { + self.0.as_predicate() + } + + fn child(&self, predicate: ty::Predicate<'tcx>) -> Self { + (predicate.expect_clause(), self.1) + } + + fn child_with_derived_cause( + &self, + predicate: ty::Predicate<'tcx>, + _span: Span, + _parent_trait_pred: ty::PolyTraitPredicate<'tcx>, + _index: usize, + ) -> Self { + (predicate.expect_clause(), self.1) + } +} + +impl<'tcx> Elaboratable<'tcx> for ty::Clause<'tcx> { + fn predicate(&self) -> ty::Predicate<'tcx> { + self.as_predicate() + } + + fn child(&self, predicate: ty::Predicate<'tcx>) -> Self { + predicate.expect_clause() + } + + fn child_with_derived_cause( + &self, + predicate: ty::Predicate<'tcx>, + _span: Span, + _parent_trait_pred: ty::PolyTraitPredicate<'tcx>, + _index: usize, + ) -> Self { + predicate.expect_clause() + } +} + pub fn elaborate<'tcx, O: Elaboratable<'tcx>>( tcx: TyCtxt<'tcx>, obligations: impl IntoIterator<Item = O>, @@ -199,7 +239,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { let bound_predicate = elaboratable.predicate().kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { // Negative trait bounds do not imply any supertrait bounds if data.polarity == ty::ImplPolarity::Negative { return; @@ -227,7 +267,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { debug!(?data, ?obligations, "super_predicates"); self.extend_deduped(obligations); } - ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) => { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) => { // Currently, we do not elaborate WF predicates, // although we easily could. } @@ -243,13 +283,13 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { // Currently, we do not "elaborate" predicates like `X -> Y`, // though conceivably we might. } - ty::PredicateKind::Clause(ty::Clause::Projection(..)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) => { // Nothing to elaborate in a projection predicate. } ty::PredicateKind::ClosureKind(..) => { // Nothing to elaborate when waiting for a closure's kind to be inferred. } - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) => { // Currently, we do not elaborate const-evaluatable // predicates. } @@ -257,10 +297,10 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { // Currently, we do not elaborate const-equate // predicates. } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) => { // Nothing to elaborate from `'a: 'b`. } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( ty_max, r_min, ))) => { @@ -292,7 +332,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { if r.is_late_bound() { None } else { - Some(ty::PredicateKind::Clause(ty::Clause::RegionOutlives( + Some(ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives( ty::OutlivesPredicate(r, r_min), ))) } @@ -300,7 +340,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { Component::Param(p) => { let ty = tcx.mk_ty_param(p.index, p.name); - Some(ty::PredicateKind::Clause(ty::Clause::TypeOutlives( + Some(ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives( ty::OutlivesPredicate(ty, r_min), ))) } @@ -310,7 +350,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { Component::Alias(alias_ty) => { // We might end up here if we have `Foo<<Bar as Baz>::Assoc>: 'a`. // With this, we can deduce that `<Bar as Baz>::Assoc: 'a`. - Some(ty::PredicateKind::Clause(ty::Clause::TypeOutlives( + Some(ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives( ty::OutlivesPredicate(alias_ty.to_ty(tcx), r_min), ))) } @@ -334,7 +374,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { ty::PredicateKind::AliasRelate(..) => { // No } - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => { // Nothing to elaborate } } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 5e3ea71f0e7..54dabb75764 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -36,7 +36,7 @@ pub type Result<T> = result::Result<T, ErrorGuaranteed>; /// Created by passing [`Config`] to [`run_compiler`]. pub struct Compiler { pub(crate) sess: Lrc<Session>, - codegen_backend: Lrc<Box<dyn CodegenBackend>>, + codegen_backend: Lrc<dyn CodegenBackend>, pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>, pub(crate) override_queries: Option<fn(&Session, &mut Providers, &mut ExternProviders)>, } @@ -45,7 +45,7 @@ impl Compiler { pub fn session(&self) -> &Lrc<Session> { &self.sess } - pub fn codegen_backend(&self) -> &Lrc<Box<dyn CodegenBackend>> { + pub fn codegen_backend(&self) -> &Lrc<dyn CodegenBackend> { &self.codegen_backend } pub fn register_lints(&self) -> &Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>> { @@ -318,7 +318,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se let compiler = Compiler { sess: Lrc::new(sess), - codegen_backend: Lrc::new(codegen_backend), + codegen_backend: Lrc::from(codegen_backend), register_lints: config.register_lints, override_queries: config.override_queries, }; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index be2af94961f..6b3facd041c 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -740,8 +740,8 @@ pub fn create_global_ctxt<'tcx>( }) } -/// Runs the resolution, type-checking, region checking and other -/// miscellaneous analysis passes on the crate. +/// Runs the type-checking, region checking and other miscellaneous analysis +/// passes on the crate. fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { rustc_passes::hir_id_validator::check_crate(tcx); diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 455a8129656..8c4cdc6696a 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -93,7 +93,6 @@ pub struct Queries<'tcx> { dep_graph: Query<DepGraph>, // This just points to what's in `gcx_cell`. gcx: Query<&'tcx GlobalCtxt<'tcx>>, - ongoing_codegen: Query<Box<dyn Any>>, } impl<'tcx> Queries<'tcx> { @@ -110,14 +109,13 @@ impl<'tcx> Queries<'tcx> { register_plugins: Default::default(), dep_graph: Default::default(), gcx: Default::default(), - ongoing_codegen: Default::default(), } } fn session(&self) -> &Lrc<Session> { &self.compiler.sess } - fn codegen_backend(&self) -> &Lrc<Box<dyn CodegenBackend>> { + fn codegen_backend(&self) -> &Lrc<dyn CodegenBackend> { self.compiler.codegen_backend() } @@ -249,23 +247,19 @@ impl<'tcx> Queries<'tcx> { }) } - pub fn ongoing_codegen(&'tcx self) -> Result<QueryResult<'_, Box<dyn Any>>> { - self.ongoing_codegen.compute(|| { - self.global_ctxt()?.enter(|tcx| { - tcx.analysis(()).ok(); + pub fn ongoing_codegen(&'tcx self) -> Result<Box<dyn Any>> { + self.global_ctxt()?.enter(|tcx| { + // Don't do code generation if there were any errors + self.session().compile_status()?; - // Don't do code generation if there were any errors - self.session().compile_status()?; + // If we have any delayed bugs, for example because we created TyKind::Error earlier, + // it's likely that codegen will only cause more ICEs, obscuring the original problem + self.session().diagnostic().flush_delayed(); - // If we have any delayed bugs, for example because we created TyKind::Error earlier, - // it's likely that codegen will only cause more ICEs, obscuring the original problem - self.session().diagnostic().flush_delayed(); + // Hook for UI tests. + Self::check_for_rustc_errors_attr(tcx); - // Hook for UI tests. - Self::check_for_rustc_errors_attr(tcx); - - Ok(passes::start_codegen(&***self.codegen_backend(), tcx)) - }) + Ok(passes::start_codegen(&**self.codegen_backend(), tcx)) }) } @@ -303,7 +297,7 @@ impl<'tcx> Queries<'tcx> { } } - pub fn linker(&'tcx self) -> Result<Linker> { + pub fn linker(&'tcx self, ongoing_codegen: Box<dyn Any>) -> Result<Linker> { let sess = self.session().clone(); let codegen_backend = self.codegen_backend().clone(); @@ -314,7 +308,6 @@ impl<'tcx> Queries<'tcx> { tcx.dep_graph.clone(), ) }); - let ongoing_codegen = self.ongoing_codegen()?.steal(); Ok(Linker { sess, @@ -331,7 +324,7 @@ impl<'tcx> Queries<'tcx> { pub struct Linker { // compilation inputs sess: Lrc<Session>, - codegen_backend: Lrc<Box<dyn CodegenBackend>>, + codegen_backend: Lrc<dyn CodegenBackend>, // compilation outputs dep_graph: DepGraph, diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 785adc0b4fb..5c5ec452850 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1592,27 +1592,27 @@ declare_lint_pass!( impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { - use rustc_middle::ty::Clause; + use rustc_middle::ty::ClauseKind; use rustc_middle::ty::PredicateKind::*; if cx.tcx.features().trivial_bounds { let predicates = cx.tcx.predicates_of(item.owner_id); for &(predicate, span) in predicates.predicates { let predicate_kind_name = match predicate.kind().skip_binder() { - Clause(Clause::Trait(..)) => "trait", - Clause(Clause::TypeOutlives(..)) | - Clause(Clause::RegionOutlives(..)) => "lifetime", + Clause(ClauseKind::Trait(..)) => "trait", + Clause(ClauseKind::TypeOutlives(..)) | + Clause(ClauseKind::RegionOutlives(..)) => "lifetime", // `ConstArgHasType` is never global as `ct` is always a param - Clause(Clause::ConstArgHasType(..)) | + Clause(ClauseKind::ConstArgHasType(..)) | // Ignore projections, as they can only be global // if the trait bound is global - Clause(Clause::Projection(..)) | - AliasRelate(..) | + Clause(ClauseKind::Projection(..)) | // Ignore bounds that a user can't type - Clause(Clause::WellFormed(..)) | + Clause(ClauseKind::WellFormed(..)) | // FIXME(generic_const_exprs): `ConstEvaluatable` can be written - Clause(Clause::ConstEvaluatable(..)) | + Clause(ClauseKind::ConstEvaluatable(..)) | + AliasRelate(..) | ObjectSafe(..) | ClosureKind(..) | Subtype(..) | @@ -1989,8 +1989,8 @@ impl ExplicitOutlivesRequirements { ) -> Vec<ty::Region<'tcx>> { inferred_outlives .iter() - .filter_map(|(clause, _)| match *clause { - ty::Clause::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a { + .filter_map(|(clause, _)| match clause.kind().skip_binder() { + ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a { ty::ReEarlyBound(ebr) if ebr.def_id == def_id => Some(b), _ => None, }, @@ -2005,8 +2005,8 @@ impl ExplicitOutlivesRequirements { ) -> Vec<ty::Region<'tcx>> { inferred_outlives .iter() - .filter_map(|(clause, _)| match *clause { - ty::Clause::TypeOutlives(ty::OutlivesPredicate(a, b)) => { + .filter_map(|(clause, _)| match clause.kind().skip_binder() { + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => { a.is_param(index).then_some(b) } _ => None, diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 15715c8fca0..63a56806a45 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { // Liberate bound regions in the predicate since we // don't actually care about lifetimes in this check. let predicate = cx.tcx.liberate_late_bound_regions(def_id, pred.kind()); - let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = predicate else { + let ty::ClauseKind::Projection(proj) = predicate else { continue; }; // Only check types, since those are the only things that may @@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { let add_bound = match (proj_term.kind(), assoc_pred.kind().skip_binder()) { ( ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), - ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)), + ty::ClauseKind::Trait(trait_pred), ) => Some(AddBound { suggest_span: cx.tcx.def_span(*def_id).shrink_to_hi(), trait_ref: trait_pred.print_modifiers_and_trait_path(), diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index 7ea1a138b7e..8aba5349578 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -87,12 +87,12 @@ declare_lint_pass!( impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { - use rustc_middle::ty::Clause; + use rustc_middle::ty::ClauseKind; use rustc_middle::ty::PredicateKind::*; let predicates = cx.tcx.explicit_predicates_of(item.owner_id); for &(predicate, span) in predicates.predicates { - let Clause(Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() else { + let Clause(ClauseKind::Trait(trait_predicate)) = predicate.kind().skip_binder() else { continue }; let def_id = trait_predicate.trait_ref.def_id; diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 9861610612f..5015b751eee 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -289,9 +289,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { .filter_only_self() .find_map(|(pred, _span)| { // We only look at the `DefId`, so it is safe to skip the binder here. - if let ty::PredicateKind::Clause(ty::Clause::Trait( - ref poly_trait_predicate, - )) = pred.kind().skip_binder() + if let ty::ClauseKind::Trait(ref poly_trait_predicate) = + pred.kind().skip_binder() { let def_id = poly_trait_predicate.trait_ref.def_id; diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 53ece08ac3d..cbb4458d1d4 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3464,7 +3464,8 @@ declare_lint! { /// out an update in your own time. pub LONG_RUNNING_CONST_EVAL, Deny, - "detects long const eval operations" + "detects long const eval operations", + report_in_external_macro } declare_lint! { diff --git a/compiler/rustc_macros/src/diagnostics/error.rs b/compiler/rustc_macros/src/diagnostics/error.rs index b37dc826d28..84b18a62028 100644 --- a/compiler/rustc_macros/src/diagnostics/error.rs +++ b/compiler/rustc_macros/src/diagnostics/error.rs @@ -54,7 +54,7 @@ fn path_to_string(path: &syn::Path) -> String { /// Returns an error diagnostic on span `span` with msg `msg`. #[must_use] -pub(crate) fn span_err(span: impl MultiSpan, msg: &str) -> Diagnostic { +pub(crate) fn span_err<T: Into<String>>(span: impl MultiSpan, msg: T) -> Diagnostic { Diagnostic::spanned(span, Level::Error, msg) } @@ -77,11 +77,9 @@ pub(crate) fn invalid_attr(attr: &Attribute) -> Diagnostic { let span = attr.span().unwrap(); let path = path_to_string(attr.path()); match attr.meta { - Meta::Path(_) => span_err(span, &format!("`#[{path}]` is not a valid attribute")), - Meta::NameValue(_) => { - span_err(span, &format!("`#[{path} = ...]` is not a valid attribute")) - } - Meta::List(_) => span_err(span, &format!("`#[{path}(...)]` is not a valid attribute")), + Meta::Path(_) => span_err(span, format!("`#[{path}]` is not a valid attribute")), + Meta::NameValue(_) => span_err(span, format!("`#[{path} = ...]` is not a valid attribute")), + Meta::List(_) => span_err(span, format!("`#[{path}(...)]` is not a valid attribute")), } } diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index e3d9eb96574..e8dc986914e 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -200,7 +200,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { throw_span_err!( attr.span().unwrap(), - &format!( + format!( "diagnostic slug must be first argument of a `#[{name}(...)]` attribute" ) ); diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 85dd9f6a3ce..12563292181 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -347,7 +347,7 @@ pub(crate) trait HasFieldMap { None => { span_err( span.unwrap(), - &format!("`{field}` doesn't refer to a field on this type"), + format!("`{field}` doesn't refer to a field on this type"), ) .emit(); quote! { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 21cbab54293..90014bd9267 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -25,7 +25,7 @@ use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::ty::codec::TyDecoder; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::GeneratorDiagnosticData; -use rustc_middle::ty::{self, ParameterizedOverTcx, Predicate, Ty, TyCtxt, Visibility}; +use rustc_middle::ty::{self, ParameterizedOverTcx, Ty, TyCtxt, Visibility}; use rustc_serialize::opaque::MemDecoder; use rustc_serialize::{Decodable, Decoder}; use rustc_session::cstore::{ @@ -642,6 +642,12 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx } } +impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Clause<'tcx>, Span)] { + fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self { + ty::codec::RefDecodable::decode(d) + } +} + impl<'a, 'tcx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyValue<T> { fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self { decoder.read_lazy() @@ -854,7 +860,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self, index: DefIndex, tcx: TyCtxt<'tcx>, - ) -> ty::EarlyBinder<&'tcx [(Predicate<'tcx>, Span)]> { + ) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> { let lazy = self.root.tables.explicit_item_bounds.get(self, index); let output = if lazy.is_default() { &mut [] diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 77f9fcfc5e6..848535fb395 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -218,6 +218,7 @@ provide! { tcx, def_id, other, cdata, thir_abstract_const => { table } optimized_mir => { table } mir_for_ctfe => { table } + closure_saved_names_of_captured_variables => { table } mir_generator_witnesses => { table } promoted_mir => { table } def_span => { table } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 9c3b8780d97..b80019bf155 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -17,9 +17,8 @@ use rustc_hir::def_id::{ CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE, }; use rustc_hir::definitions::DefPathData; -use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::intravisit; use rustc_hir::lang_items::LangItem; -use rustc_middle::hir::nested_filter; use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::{ @@ -31,7 +30,7 @@ use rustc_middle::query::Providers; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::codec::TyEncoder; use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams}; -use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt}; +use rustc_middle::ty::{self, AssocItemContainer, SymbolName, Ty, TyCtxt}; use rustc_middle::util::common::to_readable_str; use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder}; use rustc_session::config::{CrateType, OptLevel}; @@ -450,18 +449,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { LazyArray::from_position_and_num_elems(pos, len) } - fn encode_info_for_items(&mut self) { - self.encode_info_for_mod(CRATE_DEF_ID); - - // Proc-macro crates only export proc-macro items, which are looked - // up using `proc_macro_data` - if self.is_proc_macro { - return; - } - - self.tcx.hir().visit_all_item_likes_in_crate(self); - } - fn encode_def_path_table(&mut self) { let table = self.tcx.def_path_table(); if self.is_proc_macro { @@ -607,8 +594,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { _ = stat!("def-ids", || self.encode_def_ids()); - _ = stat!("items", || self.encode_info_for_items()); - let interpret_alloc_index = stat!("interpret-alloc-index", || { let mut interpret_alloc_index = Vec::new(); let mut n = 0; @@ -1138,8 +1123,8 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> | DefKind::InlineConst => true, DefKind::OpaqueTy => { - let opaque = tcx.hir().expect_item(def_id).expect_opaque_ty(); - if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = opaque.origin + let origin = tcx.opaque_type_origin(def_id); + if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin && let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id) && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() { @@ -1193,6 +1178,82 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> } } +fn should_encode_fn_sig(def_kind: DefKind) -> bool { + match def_kind { + DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) => true, + + DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Variant + | DefKind::Field + | DefKind::Const + | DefKind::Static(..) + | DefKind::Ctor(..) + | DefKind::TyAlias + | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder + | DefKind::ForeignTy + | DefKind::Impl { .. } + | DefKind::AssocConst + | DefKind::Closure + | DefKind::Generator + | DefKind::ConstParam + | DefKind::AnonConst + | DefKind::InlineConst + | DefKind::AssocTy + | DefKind::TyParam + | DefKind::Trait + | DefKind::TraitAlias + | DefKind::Mod + | DefKind::ForeignMod + | DefKind::Macro(..) + | DefKind::Use + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::ExternCrate => false, + } +} + +fn should_encode_constness(def_kind: DefKind) -> bool { + match def_kind { + DefKind::Fn + | DefKind::AssocFn + | DefKind::Closure + | DefKind::Impl { of_trait: true } + | DefKind::Variant + | DefKind::Ctor(..) => true, + + DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Field + | DefKind::Const + | DefKind::AssocConst + | DefKind::AnonConst + | DefKind::Static(..) + | DefKind::TyAlias + | DefKind::OpaqueTy + | DefKind::Impl { of_trait: false } + | DefKind::ImplTraitPlaceholder + | DefKind::ForeignTy + | DefKind::Generator + | DefKind::ConstParam + | DefKind::InlineConst + | DefKind::AssocTy + | DefKind::TyParam + | DefKind::Trait + | DefKind::TraitAlias + | DefKind::Mod + | DefKind::ForeignMod + | DefKind::Macro(..) + | DefKind::Use + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::ExternCrate => false, + } +} + fn should_encode_const(def_kind: DefKind) -> bool { match def_kind { DefKind::Const | DefKind::AssocConst | DefKind::AnonConst | DefKind::InlineConst => true, @@ -1265,10 +1326,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } fn encode_def_ids(&mut self) { + self.encode_info_for_mod(CRATE_DEF_ID); + + // Proc-macro crates only export proc-macro items, which are looked + // up using `proc_macro_data` if self.is_proc_macro { return; } + let tcx = self.tcx; + for local_id in tcx.iter_local_def_id() { let def_id = local_id.to_def_id(); let def_kind = tcx.opt_def_kind(local_id); @@ -1305,30 +1372,81 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let v = self.tcx.variances_of(def_id); record_array!(self.tables.variances_of[def_id] <- v); } + if should_encode_fn_sig(def_kind) { + record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); + } if should_encode_generics(def_kind) { let g = tcx.generics_of(def_id); record!(self.tables.generics_of[def_id] <- g); record!(self.tables.explicit_predicates_of[def_id] <- self.tcx.explicit_predicates_of(def_id)); let inferred_outlives = self.tcx.inferred_outlives_of(def_id); record_defaulted_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives); + + for param in &g.params { + if let ty::GenericParamDefKind::Const { has_default: true, .. } = param.kind { + let default = self.tcx.const_param_default(param.def_id); + record!(self.tables.const_param_default[param.def_id] <- default); + } + } } if should_encode_type(tcx, local_id, def_kind) { record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id)); } + if should_encode_constness(def_kind) { + self.tables.constness.set_some(def_id.index, self.tcx.constness(def_id)); + } + if let DefKind::Fn | DefKind::AssocFn = def_kind { + self.tables.asyncness.set_some(def_id.index, tcx.asyncness(def_id)); + record_array!(self.tables.fn_arg_names[def_id] <- tcx.fn_arg_names(def_id)); + self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id)); + } if let DefKind::TyParam = def_kind { let default = self.tcx.object_lifetime_default(def_id); record!(self.tables.object_lifetime_default[def_id] <- default); } if let DefKind::Trait = def_kind { + record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); + + let module_children = self.tcx.module_children_local(local_id); + record_array!(self.tables.module_children_non_reexports[def_id] <- + module_children.iter().map(|child| child.res.def_id().index)); } if let DefKind::TraitAlias = def_kind { + record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); record!(self.tables.implied_predicates_of[def_id] <- self.tcx.implied_predicates_of(def_id)); } + if let DefKind::Trait | DefKind::Impl { .. } = def_kind { + let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id); + record_array!(self.tables.associated_item_or_field_def_ids[def_id] <- + associated_item_def_ids.iter().map(|&def_id| { + assert!(def_id.is_local()); + def_id.index + }) + ); + for &def_id in associated_item_def_ids { + self.encode_info_for_assoc_item(def_id); + } + } + if let DefKind::Generator = def_kind { + self.encode_info_for_generator(local_id); + } if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind { self.encode_info_for_adt(local_id); } + if let DefKind::Mod = def_kind { + self.encode_info_for_mod(local_id); + } + if let DefKind::Macro(_) = def_kind { + self.encode_info_for_macro(local_id); + } + if let DefKind::OpaqueTy = def_kind { + self.encode_explicit_item_bounds(def_id); + self.tables + .is_type_alias_impl_trait + .set(def_id.index, self.tcx.is_type_alias_impl_trait(def_id)); + } if tcx.impl_method_has_trait_impl_trait_tys(def_id) && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id) { @@ -1389,26 +1507,23 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; record!(self.tables.variant_data[variant.def_id] <- data); - self.tables.constness.set_some(variant.def_id.index, hir::Constness::Const); record_array!(self.tables.associated_item_or_field_def_ids[variant.def_id] <- variant.fields.iter().map(|f| { assert!(f.did.is_local()); f.did.index })); if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor { - self.tables.constness.set_some(ctor_def_id.index, hir::Constness::Const); let fn_sig = tcx.fn_sig(ctor_def_id); - record!(self.tables.fn_sig[ctor_def_id] <- fn_sig); // FIXME only encode signature for ctor_def_id record!(self.tables.fn_sig[variant.def_id] <- fn_sig); } } } + #[instrument(level = "debug", skip(self))] fn encode_info_for_mod(&mut self, local_def_id: LocalDefId) { let tcx = self.tcx; let def_id = local_def_id.to_def_id(); - debug!("EncodeContext::encode_info_for_mod({:?})", def_id); // If we are encoding a proc-macro crates, `encode_info_for_mod` will // only ever get called for the crate root. We still want to encode @@ -1436,70 +1551,28 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record_defaulted_array!(self.tables.explicit_item_bounds[def_id] <- bounds); } - fn encode_info_for_trait_item(&mut self, def_id: DefId) { - debug!("EncodeContext::encode_info_for_trait_item({:?})", def_id); + #[instrument(level = "debug", skip(self))] + fn encode_info_for_assoc_item(&mut self, def_id: DefId) { let tcx = self.tcx; + let item = tcx.associated_item(def_id); - let defaultness = tcx.defaultness(def_id.expect_local()); - self.tables.defaultness.set_some(def_id.index, defaultness); - let trait_item = tcx.associated_item(def_id); - self.tables.assoc_container.set_some(def_id.index, trait_item.container); + self.tables.defaultness.set_some(def_id.index, item.defaultness(tcx)); + self.tables.assoc_container.set_some(def_id.index, item.container); - match trait_item.kind { - ty::AssocKind::Const => {} - ty::AssocKind::Fn => { - record_array!(self.tables.fn_arg_names[def_id] <- tcx.fn_arg_names(def_id)); - self.tables.asyncness.set_some(def_id.index, tcx.asyncness(def_id)); - self.tables.constness.set_some(def_id.index, hir::Constness::NotConst); - } - ty::AssocKind::Type => { - self.encode_explicit_item_bounds(def_id); + match item.container { + AssocItemContainer::TraitContainer => { + if let ty::AssocKind::Type = item.kind { + self.encode_explicit_item_bounds(def_id); + } } - } - if trait_item.kind == ty::AssocKind::Fn { - record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); - } - if let Some(rpitit_info) = trait_item.opt_rpitit_info { - let rpitit_info = self.lazy(rpitit_info); - self.tables.opt_rpitit_info.set_some(def_id.index, rpitit_info); - } - } - - fn encode_info_for_impl_item(&mut self, def_id: DefId) { - debug!("EncodeContext::encode_info_for_impl_item({:?})", def_id); - let tcx = self.tcx; - - let defaultness = self.tcx.defaultness(def_id.expect_local()); - self.tables.defaultness.set_some(def_id.index, defaultness); - let impl_item = self.tcx.associated_item(def_id); - self.tables.assoc_container.set_some(def_id.index, impl_item.container); - - match impl_item.kind { - ty::AssocKind::Fn => { - let (sig, body) = - self.tcx.hir().expect_impl_item(def_id.expect_local()).expect_fn(); - self.tables.asyncness.set_some(def_id.index, sig.header.asyncness); - record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); - // Can be inside `impl const Trait`, so using sig.header.constness is not reliable - let constness = if self.tcx.is_const_fn_raw(def_id) { - hir::Constness::Const - } else { - hir::Constness::NotConst - }; - self.tables.constness.set_some(def_id.index, constness); + AssocItemContainer::ImplContainer => { + if let Some(trait_item_def_id) = item.trait_item_def_id { + self.tables.trait_item_def_id.set_some(def_id.index, trait_item_def_id.into()); + } } - ty::AssocKind::Const | ty::AssocKind::Type => {} } - if let Some(trait_item_def_id) = impl_item.trait_item_def_id { - self.tables.trait_item_def_id.set_some(def_id.index, trait_item_def_id.into()); - } - if impl_item.kind == ty::AssocKind::Fn { - record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); - self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id)); - } - if let Some(rpitit_info) = impl_item.opt_rpitit_info { - let rpitit_info = self.lazy(rpitit_info); - self.tables.opt_rpitit_info.set_some(def_id.index, rpitit_info); + if let Some(rpitit_info) = item.opt_rpitit_info { + record!(self.tables.opt_rpitit_info[def_id] <- rpitit_info); } } @@ -1520,6 +1593,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { debug!("EntryBuilder::encode_mir({:?})", def_id); if encode_opt { record!(self.tables.optimized_mir[def_id.to_def_id()] <- tcx.optimized_mir(def_id)); + record!(self.tables.closure_saved_names_of_captured_variables[def_id.to_def_id()] + <- tcx.closure_saved_names_of_captured_variables(def_id)); if tcx.sess.opts.unstable_opts.drop_tracking_mir && let DefKind::Generator = self.tcx.def_kind(def_id) @@ -1570,9 +1645,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn encode_stability(&mut self, def_id: DefId) { - debug!("EncodeContext::encode_stability({:?})", def_id); - // The query lookup can take a measurable amount of time in crates with many items. Check if // the stability attributes are even enabled before using their queries. if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { @@ -1582,9 +1656,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn encode_const_stability(&mut self, def_id: DefId) { - debug!("EncodeContext::encode_const_stability({:?})", def_id); - // The query lookup can take a measurable amount of time in crates with many items. Check if // the stability attributes are even enabled before using their queries. if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { @@ -1594,9 +1667,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn encode_default_body_stability(&mut self, def_id: DefId) { - debug!("EncodeContext::encode_default_body_stability({:?})", def_id); - // The query lookup can take a measurable amount of time in crates with many items. Check if // the stability attributes are even enabled before using their queries. if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { @@ -1606,8 +1678,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn encode_deprecation(&mut self, def_id: DefId) { - debug!("EncodeContext::encode_deprecation({:?})", def_id); if let Some(depr) = self.tcx.lookup_deprecation(def_id) { record!(self.tables.lookup_deprecation_entry[def_id] <- depr); } @@ -1621,123 +1693,22 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }) } - fn encode_info_for_item(&mut self, item: &'tcx hir::Item<'tcx>) { + #[instrument(level = "debug", skip(self))] + fn encode_info_for_macro(&mut self, def_id: LocalDefId) { let tcx = self.tcx; - let def_id = item.owner_id.to_def_id(); - debug!("EncodeContext::encode_info_for_item({:?})", def_id); - - let record_associated_item_def_ids = |this: &mut Self, def_ids: &[DefId]| { - record_array!(this.tables.associated_item_or_field_def_ids[def_id] <- def_ids.iter().map(|&def_id| { - assert!(def_id.is_local()); - def_id.index - })) - }; - - match item.kind { - hir::ItemKind::Fn(ref sig, .., body) => { - self.tables.asyncness.set_some(def_id.index, sig.header.asyncness); - record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); - self.tables.constness.set_some(def_id.index, sig.header.constness); - record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); - self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id)); - } - hir::ItemKind::Macro(ref macro_def, _) => { - self.tables.is_macro_rules.set(def_id.index, macro_def.macro_rules); - record!(self.tables.macro_definition[def_id] <- &*macro_def.body); - } - hir::ItemKind::Mod(..) => { - self.encode_info_for_mod(item.owner_id.def_id); - } - hir::ItemKind::OpaqueTy(ref opaque) => { - self.encode_explicit_item_bounds(def_id); - self.tables.is_type_alias_impl_trait.set( - def_id.index, - matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. }), - ); - } - hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => { - self.tables.defaultness.set_some(def_id.index, *defaultness); - self.tables.constness.set_some(def_id.index, *constness); - self.tables.impl_polarity.set_some(def_id.index, self.tcx.impl_polarity(def_id)); - - if let Some(trait_ref) = self.tcx.impl_trait_ref(def_id) { - record!(self.tables.impl_trait_ref[def_id] <- trait_ref); - - let trait_ref = trait_ref.skip_binder(); - let trait_def = self.tcx.trait_def(trait_ref.def_id); - if let Ok(mut an) = trait_def.ancestors(self.tcx, def_id) { - if let Some(specialization_graph::Node::Impl(parent)) = an.nth(1) { - self.tables.impl_parent.set_some(def_id.index, parent.into()); - } - } - - // if this is an impl of `CoerceUnsized`, create its - // "unsized info", else just store None - if Some(trait_ref.def_id) == self.tcx.lang_items().coerce_unsized_trait() { - let coerce_unsized_info = - self.tcx.at(item.span).coerce_unsized_info(def_id); - record!(self.tables.coerce_unsized_info[def_id] <- coerce_unsized_info); - } - } - - let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id); - record_associated_item_def_ids(self, associated_item_def_ids); - for &trait_item_def_id in associated_item_def_ids { - self.encode_info_for_impl_item(trait_item_def_id); - } - } - hir::ItemKind::Trait(..) => { - record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); - let module_children = tcx.module_children_local(item.owner_id.def_id); - record_array!(self.tables.module_children_non_reexports[def_id] <- - module_children.iter().map(|child| child.res.def_id().index)); - - let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id); - record_associated_item_def_ids(self, associated_item_def_ids); - for &item_def_id in associated_item_def_ids { - self.encode_info_for_trait_item(item_def_id); - } - } - hir::ItemKind::TraitAlias(..) => { - record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); - } - hir::ItemKind::ExternCrate(_) - | hir::ItemKind::Use(..) - | hir::ItemKind::Static(..) - | hir::ItemKind::Const(..) - | hir::ItemKind::Enum(..) - | hir::ItemKind::Struct(..) - | hir::ItemKind::Union(..) - | hir::ItemKind::ForeignMod { .. } - | hir::ItemKind::GlobalAsm(..) - | hir::ItemKind::TyAlias(..) => {} - } + let hir::ItemKind::Macro(ref macro_def, _) = tcx.hir().expect_item(def_id).kind else { bug!() }; + self.tables.is_macro_rules.set(def_id.local_def_index, macro_def.macro_rules); + record!(self.tables.macro_definition[def_id.to_def_id()] <- &*macro_def.body); } #[instrument(level = "debug", skip(self))] - fn encode_info_for_closure(&mut self, def_id: LocalDefId) { - // NOTE(eddyb) `tcx.type_of(def_id)` isn't used because it's fully generic, - // including on the signature, which is inferred in `typeck`. + fn encode_info_for_generator(&mut self, def_id: LocalDefId) { let typeck_result: &'tcx ty::TypeckResults<'tcx> = self.tcx.typeck(def_id); - let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); - let ty = typeck_result.node_type(hir_id); - match ty.kind() { - ty::Generator(..) => { - let data = self.tcx.generator_kind(def_id).unwrap(); - let generator_diagnostic_data = typeck_result.get_generator_diagnostic_data(); - record!(self.tables.generator_kind[def_id.to_def_id()] <- data); - record!(self.tables.generator_diagnostic_data[def_id.to_def_id()] <- generator_diagnostic_data); - } - - ty::Closure(_, substs) => { - let constness = self.tcx.constness(def_id.to_def_id()); - self.tables.constness.set_some(def_id.to_def_id().index, constness); - record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder::bind(substs.as_closure().sig())); - } - - _ => bug!("closure that is neither generator nor closure"), - } + let data = self.tcx.generator_kind(def_id).unwrap(); + let generator_diagnostic_data = typeck_result.get_generator_diagnostic_data(); + record!(self.tables.generator_kind[def_id.to_def_id()] <- data); + record!(self.tables.generator_diagnostic_data[def_id.to_def_id()] <- generator_diagnostic_data); } fn encode_native_libraries(&mut self) -> LazyArray<NativeLib> { @@ -1958,28 +1929,43 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } /// Encodes an index, mapping each trait to its (local) implementations. + #[instrument(level = "debug", skip(self))] fn encode_impls(&mut self) -> LazyArray<TraitImpls> { - debug!("EncodeContext::encode_traits_and_impls()"); empty_proc_macro!(self); let tcx = self.tcx; let mut fx_hash_map: FxHashMap<DefId, Vec<(DefIndex, Option<SimplifiedType>)>> = FxHashMap::default(); for id in tcx.hir().items() { - if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. }) { - if let Some(trait_ref) = tcx.impl_trait_ref(id.owner_id) { - let trait_ref = trait_ref.subst_identity(); - - let simplified_self_ty = fast_reject::simplify_type( - self.tcx, - trait_ref.self_ty(), - TreatParams::AsCandidateKey, - ); - - fx_hash_map - .entry(trait_ref.def_id) - .or_default() - .push((id.owner_id.def_id.local_def_index, simplified_self_ty)); + let DefKind::Impl { of_trait } = tcx.def_kind(id.owner_id) else { continue; }; + let def_id = id.owner_id.to_def_id(); + + self.tables.defaultness.set_some(def_id.index, tcx.defaultness(def_id)); + self.tables.impl_polarity.set_some(def_id.index, tcx.impl_polarity(def_id)); + + if of_trait && let Some(trait_ref) = tcx.impl_trait_ref(def_id) { + record!(self.tables.impl_trait_ref[def_id] <- trait_ref); + + let trait_ref = trait_ref.subst_identity(); + let simplified_self_ty = + fast_reject::simplify_type(self.tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey); + fx_hash_map + .entry(trait_ref.def_id) + .or_default() + .push((id.owner_id.def_id.local_def_index, simplified_self_ty)); + + let trait_def = tcx.trait_def(trait_ref.def_id); + if let Some(mut an) = trait_def.ancestors(tcx, def_id).ok() { + if let Some(specialization_graph::Node::Impl(parent)) = an.nth(1) { + self.tables.impl_parent.set_some(def_id.index, parent.into()); + } + } + + // if this is an impl of `CoerceUnsized`, create its + // "unsized info", else just store None + if Some(trait_ref.def_id) == tcx.lang_items().coerce_unsized_trait() { + let coerce_unsized_info = tcx.coerce_unsized_info(def_id); + record!(self.tables.coerce_unsized_info[def_id] <- coerce_unsized_info); } } } @@ -2007,8 +1993,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy_array(&all_impls) } + #[instrument(level = "debug", skip(self))] fn encode_incoherent_impls(&mut self) -> LazyArray<IncoherentImpls> { - debug!("EncodeContext::encode_traits_and_impls()"); empty_proc_macro!(self); let tcx = self.tcx; let mut all_impls: Vec<_> = tcx.crate_inherent_impls(()).incoherent_impls.iter().collect(); @@ -2077,77 +2063,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } LazyArray::default() } - - fn encode_info_for_foreign_item(&mut self, def_id: DefId, nitem: &hir::ForeignItem<'_>) { - let tcx = self.tcx; - - debug!("EncodeContext::encode_info_for_foreign_item({:?})", def_id); - - match nitem.kind { - hir::ForeignItemKind::Fn(_, ref names, _) => { - self.tables.asyncness.set_some(def_id.index, hir::IsAsync::NotAsync); - record_array!(self.tables.fn_arg_names[def_id] <- *names); - let constness = if self.tcx.is_const_fn_raw(def_id) { - hir::Constness::Const - } else { - hir::Constness::NotConst - }; - self.tables.constness.set_some(def_id.index, constness); - record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); - } - hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => {} - } - if let hir::ForeignItemKind::Fn(..) = nitem.kind { - self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id)); - } - } -} - -// FIXME(eddyb) make metadata encoding walk over all definitions, instead of HIR. -impl<'a, 'tcx> Visitor<'tcx> for EncodeContext<'a, 'tcx> { - type NestedFilter = nested_filter::OnlyBodies; - - fn nested_visit_map(&mut self) -> Self::Map { - self.tcx.hir() - } - fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { - intravisit::walk_expr(self, ex); - self.encode_info_for_expr(ex); - } - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - intravisit::walk_item(self, item); - self.encode_info_for_item(item); - } - fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem<'tcx>) { - intravisit::walk_foreign_item(self, ni); - self.encode_info_for_foreign_item(ni.owner_id.to_def_id(), ni); - } - fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { - intravisit::walk_generics(self, generics); - self.encode_info_for_generics(generics); - } -} - -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { - fn encode_info_for_generics(&mut self, generics: &hir::Generics<'tcx>) { - for param in generics.params { - match param.kind { - hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => {} - hir::GenericParamKind::Const { ref default, .. } => { - let def_id = param.def_id.to_def_id(); - if default.is_some() { - record!(self.tables.const_param_default[def_id] <- self.tcx.const_param_default(def_id)) - } - } - } - } - } - - fn encode_info_for_expr(&mut self, expr: &hir::Expr<'_>) { - if let hir::ExprKind::Closure(closure) = expr.kind { - self.encode_info_for_closure(closure.def_id); - } - } } /// Used to prefetch queries which will be needed later by metadata encoding. diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 66048f3ece7..9cffd96f4a3 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -32,7 +32,7 @@ use rustc_span::edition::Edition; use rustc_span::hygiene::{ExpnIndex, MacroKind}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Span}; -use rustc_target::abi::VariantIdx; +use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_target::spec::{PanicStrategy, TargetTriple}; use std::marker::PhantomData; @@ -375,7 +375,7 @@ define_tables! { is_type_alias_impl_trait: Table<DefIndex, bool>, attr_flags: Table<DefIndex, AttrFlags>, def_path_hashes: Table<DefIndex, DefPathHash>, - explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>, + explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>, inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>, inherent_impls: Table<DefIndex, LazyArray<DefIndex>>, associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>, @@ -416,6 +416,7 @@ define_tables! { object_lifetime_default: Table<DefIndex, LazyValue<ObjectLifetimeDefault>>, optimized_mir: Table<DefIndex, LazyValue<mir::Body<'static>>>, mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>, + closure_saved_names_of_captured_variables: Table<DefIndex, LazyValue<IndexVec<FieldIdx, Symbol>>>, mir_generator_witnesses: Table<DefIndex, LazyValue<mir::GeneratorLayout<'static>>>, promoted_mir: Table<DefIndex, LazyValue<IndexVec<mir::Promoted, mir::Body<'static>>>>, thir_abstract_const: Table<DefIndex, LazyValue<ty::EarlyBinder<ty::Const<'static>>>>, diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 6c404fbb7c6..ac4cef34fdd 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -27,6 +27,11 @@ macro_rules! arena_types { rustc_middle::mir::Promoted, rustc_middle::mir::Body<'tcx> >, + [decode] closure_debuginfo: + rustc_index::IndexVec< + rustc_target::abi::FieldIdx, + rustc_span::symbol::Symbol, + >, [decode] typeck_results: rustc_middle::ty::TypeckResults<'tcx>, [decode] borrowck_result: rustc_middle::mir::BorrowCheckResult<'tcx>, diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 6aa20dbed92..669c609d995 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2035,23 +2035,19 @@ impl<'tcx> Rvalue<'tcx> { impl BorrowKind { pub fn mutability(&self) -> Mutability { match *self { - BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => Mutability::Not, + BorrowKind::Shared | BorrowKind::Shallow => Mutability::Not, BorrowKind::Mut { .. } => Mutability::Mut, } } pub fn allows_two_phase_borrow(&self) -> bool { match *self { - BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => false, - BorrowKind::Mut { allow_two_phase_borrow } => allow_two_phase_borrow, - } - } - - // FIXME: won't be used after diagnostic migration - pub fn describe_mutability(&self) -> &str { - match *self { - BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => "immutable", - BorrowKind::Mut { .. } => "mutable", + BorrowKind::Shared + | BorrowKind::Shallow + | BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture } => { + false + } + BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow } => true, } } } @@ -2090,7 +2086,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { let kind_str = match borrow_kind { BorrowKind::Shared => "", BorrowKind::Shallow => "shallow ", - BorrowKind::Mut { .. } | BorrowKind::Unique => "mut ", + BorrowKind::Mut { .. } => "mut ", }; // When printing regions, add trailing space if necessary. diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 1511e255235..ca735d52314 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -231,7 +231,7 @@ pub struct CodegenUnit<'tcx> { /// as well as the crate name and disambiguator. name: Symbol, items: FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)>, - size_estimate: Option<usize>, + size_estimate: usize, primary: bool, /// True if this is CGU is used to hold code coverage information for dead code, /// false otherwise. @@ -269,7 +269,7 @@ impl<'tcx> CodegenUnit<'tcx> { CodegenUnit { name, items: Default::default(), - size_estimate: None, + size_estimate: 0, primary: false, is_code_coverage_dead_code_cgu: false, } @@ -320,23 +320,21 @@ impl<'tcx> CodegenUnit<'tcx> { base_n::encode(hash, base_n::CASE_INSENSITIVE) } - pub fn create_size_estimate(&mut self, tcx: TyCtxt<'tcx>) { + pub fn compute_size_estimate(&mut self, tcx: TyCtxt<'tcx>) { // Estimate the size of a codegen unit as (approximately) the number of MIR // statements it corresponds to. - self.size_estimate = Some(self.items.keys().map(|mi| mi.size_estimate(tcx)).sum()); + self.size_estimate = self.items.keys().map(|mi| mi.size_estimate(tcx)).sum(); } #[inline] - /// Should only be called if [`create_size_estimate`] has previously been called. + /// Should only be called if [`compute_size_estimate`] has previously been called. /// - /// [`create_size_estimate`]: Self::create_size_estimate + /// [`compute_size_estimate`]: Self::compute_size_estimate pub fn size_estimate(&self) -> usize { + // Items are never zero-sized, so if we have items the estimate must be + // non-zero, unless we forgot to call `compute_size_estimate` first. + assert!(self.items.is_empty() || self.size_estimate != 0); self.size_estimate - .expect("create_size_estimate must be called before getting a size_estimate") - } - - pub fn modify_size_estimate(&mut self, delta: usize) { - *self.size_estimate.as_mut().unwrap() += delta; } pub fn contains_item(&self, item: &MonoItem<'tcx>) -> bool { diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index a15c419da7a..13a1011e328 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -9,6 +9,7 @@ use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::BitMatrix; use rustc_index::{Idx, IndexVec}; +use rustc_span::symbol::Symbol; use rustc_span::Span; use rustc_target::abi::{FieldIdx, VariantIdx}; use smallvec::SmallVec; @@ -150,6 +151,9 @@ pub struct GeneratorLayout<'tcx> { /// The type of every local stored inside the generator. pub field_tys: IndexVec<GeneratorSavedLocal, GeneratorSavedTy<'tcx>>, + /// The name for debuginfo. + pub field_names: IndexVec<GeneratorSavedLocal, Option<Symbol>>, + /// Which of the above fields are in each variant. Note that one field may /// be stored in multiple variants. pub variant_fields: IndexVec<VariantIdx, IndexVec<FieldIdx, GeneratorSavedLocal>>, diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 1a65f74f4fe..abb3b3d953b 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -182,6 +182,16 @@ pub enum BorrowKind { /// We can also report errors with this kind of borrow differently. Shallow, + /// Data is mutable and not aliasable. + Mut { kind: MutBorrowKind }, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)] +#[derive(Hash, HashStable)] +pub enum MutBorrowKind { + Default, + /// This borrow arose from method-call auto-ref. (i.e., `adjustment::Adjust::Borrow`) + TwoPhaseBorrow, /// Data must be immutable but not aliasable. This kind of borrow /// cannot currently be expressed by the user and is used only in /// implicit closure bindings. It is needed when the closure is @@ -216,23 +226,14 @@ pub enum BorrowKind { /// user code, if awkward, but extra weird for closures, since the /// borrow is hidden. /// - /// So we introduce a "unique imm" borrow -- the referent is - /// immutable, but not aliasable. This solves the problem. For - /// simplicity, we don't give users the way to express this - /// borrow, it's just used when translating closures. + /// So we introduce a `ClosureCapture` borrow -- user will not have to mark the variable + /// containing the mutable reference as `mut`, as they didn't ever + /// intend to mutate the mutable reference itself. We still mutable capture it in order to + /// mutate the pointed value through it (but not mutating the reference itself). /// - // FIXME(#112072): This is wrong. Unique borrows are mutable borrows except - // that they do not require their pointee to be marked as a mutable. - // They should still be treated as mutable borrows in every other way, - // e.g. for variance or overlap checking. - Unique, - - /// Data is mutable and not aliasable. - Mut { - /// `true` if this borrow arose from method-call auto-ref - /// (i.e., `adjustment::Adjust::Borrow`). - allow_two_phase_borrow: bool, - }, + /// This solves the problem. For simplicity, we don't give users the way to express this + /// borrow, it's just used when translating closures. + ClosureCapture, } /////////////////////////////////////////////////////////////////////////// @@ -512,6 +513,31 @@ pub struct CopyNonOverlapping<'tcx> { pub count: Operand<'tcx>, } +/// Represents how a `TerminatorKind::Call` was constructed, used for diagnostics +#[derive(Clone, Copy, TyEncodable, TyDecodable, Debug, PartialEq, Hash, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] +pub enum CallSource { + /// This came from something such as `a > b` or `a + b`. In THIR, if `from_hir_call` + /// is false then this is the desugaring. + OverloadedOperator, + /// This was from comparison generated by a match, used by const-eval for better errors + /// when the comparison cannot be done in compile time. + /// + /// (see <https://github.com/rust-lang/rust/issues/90237>) + MatchCmp, + /// Other types of desugaring that did not come from the HIR, but we don't care about + /// for diagnostics (yet). + Misc, + /// Normal function call, no special source + Normal, +} + +impl CallSource { + pub fn from_hir_call(self) -> bool { + matches!(self, CallSource::Normal) + } +} + /////////////////////////////////////////////////////////////////////////// // Terminators @@ -638,11 +664,10 @@ pub enum TerminatorKind<'tcx> { target: Option<BasicBlock>, /// Action to be taken if the call unwinds. unwind: UnwindAction, - /// `true` if this is from a call in HIR rather than from an overloaded - /// operator. True for overloaded function call. - from_hir_call: bool, + /// Where this call came from in HIR/THIR. + call_source: CallSource, /// This `Span` is the span of the function, without the dot and receiver - /// (e.g. `foo(a, b)` in `x.foo(a, b)` + /// e.g. `foo(a, b)` in `x.foo(a, b)` fn_span: Span, }, @@ -1267,10 +1292,16 @@ pub enum UnOp { pub enum BinOp { /// The `+` operator (addition) Add, + /// Like `Add`, but with UB on overflow. (Integers only.) + AddUnchecked, /// The `-` operator (subtraction) Sub, + /// Like `Sub`, but with UB on overflow. (Integers only.) + SubUnchecked, /// The `*` operator (multiplication) Mul, + /// Like `Mul`, but with UB on overflow. (Integers only.) + MulUnchecked, /// The `/` operator (division) /// /// For integer types, division by zero is UB, as is `MIN / -1` for signed. @@ -1296,10 +1327,17 @@ pub enum BinOp { /// /// The offset is truncated to the size of the first operand before shifting. Shl, + /// Like `Shl`, but is UB if the RHS >= LHS::BITS + ShlUnchecked, /// The `>>` operator (shift right) /// /// The offset is truncated to the size of the first operand before shifting. + /// + /// This is an arithmetic shift if the LHS is signed + /// and a logical shift if the LHS is unsigned. Shr, + /// Like `Shl`, but is UB if the RHS >= LHS::BITS + ShrUnchecked, /// The `==` operator (equality) Eq, /// The `<` operator (less than) diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 5ca82413448..65dff193c80 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -235,8 +235,11 @@ impl<'tcx> BinOp { // FIXME: handle SIMD correctly match self { &BinOp::Add + | &BinOp::AddUnchecked | &BinOp::Sub + | &BinOp::SubUnchecked | &BinOp::Mul + | &BinOp::MulUnchecked | &BinOp::Div | &BinOp::Rem | &BinOp::BitXor @@ -246,7 +249,11 @@ impl<'tcx> BinOp { assert_eq!(lhs_ty, rhs_ty); lhs_ty } - &BinOp::Shl | &BinOp::Shr | &BinOp::Offset => { + &BinOp::Shl + | &BinOp::ShlUnchecked + | &BinOp::Shr + | &BinOp::ShrUnchecked + | &BinOp::Offset => { lhs_ty // lhs_ty can be != rhs_ty } &BinOp::Eq | &BinOp::Lt | &BinOp::Le | &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => { @@ -262,11 +269,6 @@ impl BorrowKind { BorrowKind::Mut { .. } => hir::Mutability::Mut, BorrowKind::Shared => hir::Mutability::Not, - // We have no type corresponding to a unique imm borrow, so - // use `&mut`. It gives all the capabilities of a `&uniq` - // and hence is a safe "over approximation". - BorrowKind::Unique => hir::Mutability::Mut, - // We have no type corresponding to a shallow borrow, so use // `&` as an approximation. BorrowKind::Shallow => hir::Mutability::Not, @@ -293,7 +295,14 @@ impl BinOp { BinOp::Gt => hir::BinOpKind::Gt, BinOp::Le => hir::BinOpKind::Le, BinOp::Ge => hir::BinOpKind::Ge, - BinOp::Offset => unreachable!(), + BinOp::AddUnchecked + | BinOp::SubUnchecked + | BinOp::MulUnchecked + | BinOp::ShlUnchecked + | BinOp::ShrUnchecked + | BinOp::Offset => { + unreachable!() + } } } } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 8d44e929afd..b030d1e6c3e 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -519,7 +519,7 @@ macro_rules! make_mir_visitor { destination, target: _, unwind: _, - from_hir_call: _, + call_source: _, fn_span: _ } => { self.visit_operand(func, location); @@ -650,9 +650,6 @@ macro_rules! make_mir_visitor { BorrowKind::Shallow => PlaceContext::NonMutatingUse( NonMutatingUseContext::ShallowBorrow ), - BorrowKind::Unique => PlaceContext::MutatingUse( - MutatingUseContext::Borrow - ), BorrowKind::Mut { .. } => PlaceContext::MutatingUse(MutatingUseContext::Borrow), }; diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index fd02a16130f..f1ae4942b7b 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -55,6 +55,10 @@ impl<T> EraseType for &'_ ty::List<T> { type Result = [u8; size_of::<*const ()>()]; } +impl<I: rustc_index::Idx, T> EraseType for &'_ rustc_index::IndexSlice<I, T> { + type Result = [u8; size_of::<&'static rustc_index::IndexSlice<u32, ()>>()]; +} + impl<T> EraseType for Result<&'_ T, traits::query::NoSolution> { type Result = [u8; size_of::<Result<&'static (), traits::query::NoSolution>>()]; } @@ -317,7 +321,7 @@ tcx_lifetime! { rustc_middle::traits::query::type_op::Subtype, rustc_middle::ty::AdtDef, rustc_middle::ty::AliasTy, - rustc_middle::ty::Clause, + rustc_middle::ty::ClauseKind, rustc_middle::ty::ClosureTypeInfo, rustc_middle::ty::Const, rustc_middle::ty::DestructuredConst, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 132b11b29eb..5d6a477b9ad 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -346,7 +346,7 @@ rustc_queries! { /// `key` is the `DefId` of the associated type or opaque type. /// /// Bounds from the parent (e.g. with nested impl trait) are not included. - query explicit_item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Predicate<'tcx>, Span)]> { + query explicit_item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> { desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern @@ -373,7 +373,7 @@ rustc_queries! { /// ``` /// /// Bounds from the parent (e.g. with nested impl trait) are not included. - query item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Predicate<'tcx>>> { + query item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Clause<'tcx>>> { desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) } } @@ -531,6 +531,19 @@ rustc_queries! { } } + /// Returns names of captured upvars for closures and generators. + /// + /// Here are some examples: + /// - `name__field1__field2` when the upvar is captured by value. + /// - `_ref__name__field` when the upvar is captured by reference. + /// + /// For generators this only contains upvars that are shared by all states. + query closure_saved_names_of_captured_variables(def_id: DefId) -> &'tcx IndexVec<abi::FieldIdx, Symbol> { + arena_cache + desc { |tcx| "computing debuginfo for closure `{}`", tcx.def_path_str(def_id) } + separate_provide_extern + } + query mir_generator_witnesses(key: DefId) -> &'tcx Option<mir::GeneratorLayout<'tcx>> { arena_cache desc { |tcx| "generator witness types for `{}`", tcx.def_path_str(key) } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 492b7228488..f0380204970 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -981,7 +981,7 @@ pub enum CodegenObligationError { FulfillmentError, } -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] pub enum DefiningAnchor { /// `DefId` of the item. Bind(LocalDefId), diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index eae5a280e11..60a38747fdf 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -92,7 +92,7 @@ pub type CanonicalTypeOpProvePredicateGoal<'tcx> = pub type CanonicalTypeOpNormalizeGoal<'tcx, T> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>; -#[derive(Copy, Clone, Debug, HashStable, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, Hash, HashStable, PartialEq, Eq)] pub struct NoSolution; impl<'tcx> From<TypeError<'tcx>> for NoSolution { diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 2c5b64a59cd..73b332fd8ec 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -11,6 +11,8 @@ use crate::ty::{ TypeVisitor, }; +pub mod inspect; + pub type EvaluationCache<'tcx> = Cache<CanonicalInput<'tcx>, QueryResult<'tcx>>; /// A goal is a statement, i.e. `predicate`, we want to prove @@ -18,7 +20,7 @@ pub type EvaluationCache<'tcx> = Cache<CanonicalInput<'tcx>, QueryResult<'tcx>>; /// /// Most of the time the `param_env` contains the `where`-bounds of the function /// we're currently typechecking while the `predicate` is some trait bound. -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct Goal<'tcx, P> { pub predicate: P, pub param_env: ty::ParamEnv<'tcx>, @@ -39,7 +41,7 @@ impl<'tcx, P> Goal<'tcx, P> { } } -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct Response<'tcx> { pub certainty: Certainty, pub var_values: CanonicalVarValues<'tcx>, @@ -47,7 +49,7 @@ pub struct Response<'tcx> { pub external_constraints: ExternalConstraints<'tcx>, } -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] pub enum Certainty { Yes, Maybe(MaybeCause), @@ -86,7 +88,7 @@ impl Certainty { } /// Why we failed to evaluate a goal. -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] pub enum MaybeCause { /// We failed due to ambiguity. This ambiguity can either /// be a true ambiguity, i.e. there are multiple different answers, @@ -96,7 +98,7 @@ pub enum MaybeCause { Overflow, } -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct QueryInput<'tcx, T> { pub goal: Goal<'tcx, T>, pub anchor: DefiningAnchor, @@ -104,12 +106,12 @@ pub struct QueryInput<'tcx, T> { } /// Additional constraints returned on success. -#[derive(Debug, PartialEq, Eq, Clone, Hash, Default)] +#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)] pub struct PredefinedOpaquesData<'tcx> { pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>, } -#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] +#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)] pub struct PredefinedOpaques<'tcx>(pub(crate) Interned<'tcx, PredefinedOpaquesData<'tcx>>); impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> { @@ -132,7 +134,7 @@ pub type CanonicalResponse<'tcx> = Canonical<'tcx, Response<'tcx>>; /// solver, merge the two responses again. pub type QueryResult<'tcx> = Result<CanonicalResponse<'tcx>, NoSolution>; -#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] +#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)] pub struct ExternalConstraints<'tcx>(pub(crate) Interned<'tcx, ExternalConstraintsData<'tcx>>); impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> { @@ -144,7 +146,7 @@ impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> { } /// Additional constraints returned on success. -#[derive(Debug, PartialEq, Eq, Clone, Hash, Default)] +#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)] pub struct ExternalConstraintsData<'tcx> { // FIXME: implement this. pub region_constraints: QueryRegionConstraints<'tcx>, @@ -226,3 +228,9 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> { self.opaque_types.visit_with(visitor) } } + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)] +pub enum IsNormalizesToHack { + Yes, + No, +} diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs new file mode 100644 index 00000000000..527afa005b9 --- /dev/null +++ b/compiler/rustc_middle/src/traits/solve/inspect.rs @@ -0,0 +1,83 @@ +use super::{ + CanonicalInput, Certainty, Goal, IsNormalizesToHack, NoSolution, QueryInput, QueryResult, +}; +use crate::ty; +use format::ProofTreeFormatter; +use std::fmt::{Debug, Write}; + +mod format; + +#[derive(Eq, PartialEq, Debug, Hash, HashStable)] +pub enum CacheHit { + Provisional, + Global, +} + +#[derive(Eq, PartialEq, Hash, HashStable)] +pub struct GoalEvaluation<'tcx> { + pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>, + pub canonicalized_goal: CanonicalInput<'tcx>, + + pub kind: GoalEvaluationKind<'tcx>, + pub is_normalizes_to_hack: IsNormalizesToHack, + pub returned_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>, + + pub result: QueryResult<'tcx>, +} + +#[derive(Eq, PartialEq, Hash, HashStable)] +pub enum GoalEvaluationKind<'tcx> { + CacheHit(CacheHit), + Uncached { revisions: Vec<GoalEvaluationStep<'tcx>> }, +} +impl Debug for GoalEvaluation<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + ProofTreeFormatter { f, on_newline: true }.format_goal_evaluation(self) + } +} + +#[derive(Eq, PartialEq, Hash, HashStable)] +pub struct AddedGoalsEvaluation<'tcx> { + pub evaluations: Vec<Vec<GoalEvaluation<'tcx>>>, + pub result: Result<Certainty, NoSolution>, +} +impl Debug for AddedGoalsEvaluation<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + ProofTreeFormatter { f, on_newline: true }.format_nested_goal_evaluation(self) + } +} + +#[derive(Eq, PartialEq, Hash, HashStable)] +pub struct GoalEvaluationStep<'tcx> { + pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>, + + pub nested_goal_evaluations: Vec<AddedGoalsEvaluation<'tcx>>, + pub candidates: Vec<GoalCandidate<'tcx>>, + + pub result: QueryResult<'tcx>, +} +impl Debug for GoalEvaluationStep<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + ProofTreeFormatter { f, on_newline: true }.format_evaluation_step(self) + } +} + +#[derive(Eq, PartialEq, Hash, HashStable)] +pub struct GoalCandidate<'tcx> { + pub nested_goal_evaluations: Vec<AddedGoalsEvaluation<'tcx>>, + pub candidates: Vec<GoalCandidate<'tcx>>, + pub kind: CandidateKind<'tcx>, +} + +#[derive(Eq, PartialEq, Debug, Hash, HashStable)] +pub enum CandidateKind<'tcx> { + /// Probe entered when normalizing the self ty during candidate assembly + NormalizedSelfTyAssembly, + /// A normal candidate for proving a goal + Candidate { name: String, result: QueryResult<'tcx> }, +} +impl Debug for GoalCandidate<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + ProofTreeFormatter { f, on_newline: true }.format_candidate(self) + } +} diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs new file mode 100644 index 00000000000..2ee625674fa --- /dev/null +++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs @@ -0,0 +1,131 @@ +use super::*; + +pub(super) struct ProofTreeFormatter<'a, 'b> { + pub(super) f: &'a mut (dyn Write + 'b), + pub(super) on_newline: bool, +} + +impl Write for ProofTreeFormatter<'_, '_> { + fn write_str(&mut self, s: &str) -> std::fmt::Result { + for line in s.split_inclusive("\n") { + if self.on_newline { + self.f.write_str(" ")?; + } + self.on_newline = line.ends_with("\n"); + self.f.write_str(line)?; + } + + Ok(()) + } +} + +impl ProofTreeFormatter<'_, '_> { + fn nested(&mut self) -> ProofTreeFormatter<'_, '_> { + ProofTreeFormatter { f: self, on_newline: true } + } + + pub(super) fn format_goal_evaluation(&mut self, goal: &GoalEvaluation<'_>) -> std::fmt::Result { + let f = &mut *self.f; + + let goal_text = match goal.is_normalizes_to_hack { + IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL", + IsNormalizesToHack::No => "GOAL", + }; + + writeln!(f, "{}: {:?}", goal_text, goal.uncanonicalized_goal,)?; + writeln!(f, "CANONICALIZED: {:?}", goal.canonicalized_goal)?; + + match &goal.kind { + GoalEvaluationKind::CacheHit(CacheHit::Global) => { + writeln!(f, "GLOBAL CACHE HIT: {:?}", goal.result) + } + GoalEvaluationKind::CacheHit(CacheHit::Provisional) => { + writeln!(f, "PROVISIONAL CACHE HIT: {:?}", goal.result) + } + GoalEvaluationKind::Uncached { revisions } => { + for (n, step) in revisions.iter().enumerate() { + let f = &mut *self.f; + writeln!(f, "REVISION {n}: {:?}", step.result)?; + let mut f = self.nested(); + f.format_evaluation_step(step)?; + } + + let f = &mut *self.f; + writeln!(f, "RESULT: {:?}", goal.result) + } + }?; + + if goal.returned_goals.len() > 0 { + let f = &mut *self.f; + writeln!(f, "NESTED GOALS ADDED TO CALLER: [")?; + let mut f = self.nested(); + for goal in goal.returned_goals.iter() { + writeln!(f, "ADDED GOAL: {:?},", goal)?; + } + writeln!(self.f, "]")?; + } + + Ok(()) + } + + pub(super) fn format_evaluation_step( + &mut self, + evaluation_step: &GoalEvaluationStep<'_>, + ) -> std::fmt::Result { + let f = &mut *self.f; + writeln!(f, "INSTANTIATED: {:?}", evaluation_step.instantiated_goal)?; + + for candidate in &evaluation_step.candidates { + let mut f = self.nested(); + f.format_candidate(candidate)?; + } + for nested_goal_evaluation in &evaluation_step.nested_goal_evaluations { + let mut f = self.nested(); + f.format_nested_goal_evaluation(nested_goal_evaluation)?; + } + + Ok(()) + } + + pub(super) fn format_candidate(&mut self, candidate: &GoalCandidate<'_>) -> std::fmt::Result { + let f = &mut *self.f; + + match &candidate.kind { + CandidateKind::NormalizedSelfTyAssembly => { + writeln!(f, "NORMALIZING SELF TY FOR ASSEMBLY:") + } + CandidateKind::Candidate { name, result } => { + writeln!(f, "CANDIDATE {}: {:?}", name, result) + } + }?; + + let mut f = self.nested(); + for candidate in &candidate.candidates { + f.format_candidate(candidate)?; + } + for nested_evaluations in &candidate.nested_goal_evaluations { + f.format_nested_goal_evaluation(nested_evaluations)?; + } + + Ok(()) + } + + pub(super) fn format_nested_goal_evaluation( + &mut self, + nested_goal_evaluation: &AddedGoalsEvaluation<'_>, + ) -> std::fmt::Result { + let f = &mut *self.f; + writeln!(f, "TRY_EVALUATE_ADDED_GOALS: {:?}", nested_goal_evaluation.result)?; + + for (n, revision) in nested_goal_evaluation.evaluations.iter().enumerate() { + let f = &mut *self.f; + writeln!(f, "REVISION {n}")?; + let mut f = self.nested(); + for goal_evaluation in revision { + f.format_goal_evaluation(goal_evaluation)?; + } + } + + Ok(()) + } +} diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index be7b2b7ec67..bc927374549 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -427,6 +427,8 @@ pub enum BorrowKind { /// immutable, but not aliasable. This solves the problem. For /// simplicity, we don't give users the way to express this /// borrow, it's just used when translating closures. + /// + /// FIXME: Rename this to indicate the borrow is actually not immutable. UniqueImmBorrow, /// Data is mutable and not aliasable. diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 76f52bc34ed..248251e1ef5 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -128,6 +128,12 @@ impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Predicate<'tcx> } } +impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Clause<'tcx> { + fn encode(&self, e: &mut E) { + self.as_predicate().encode(e); + } +} + impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Region<'tcx> { fn encode(&self, e: &mut E) { self.kind().encode(e); @@ -241,6 +247,13 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Predicate<'tcx> } } +impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Clause<'tcx> { + fn decode(decoder: &mut D) -> ty::Clause<'tcx> { + let pred: ty::Predicate<'tcx> = Decodable::decode(decoder); + pred.expect_clause() + } +} + impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for SubstsRef<'tcx> { fn decode(decoder: &mut D) -> Self { let len = decoder.read_usize(); diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 449129b8418..1f9cf2c6448 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -25,10 +25,10 @@ use crate::traits::solve::{ ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, PredefinedOpaquesData, }; use crate::ty::{ - self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, FloatTy, FloatVar, FloatVid, - GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, - PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, ReprOptions, - TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy, Visibility, + self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Const, ConstData, FloatTy, FloatVar, + FloatVid, GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst, + ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, + ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy, Visibility, }; use crate::ty::{GenericArg, InternalSubsts, SubstsRef}; use rustc_ast::{self as ast, attr}; @@ -141,7 +141,9 @@ pub struct CtxtInterners<'tcx> { region: InternedSet<'tcx, RegionKind<'tcx>>, poly_existential_predicates: InternedSet<'tcx, List<PolyExistentialPredicate<'tcx>>>, predicate: InternedSet<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>, + // FIXME(clause): remove this when all usages are moved to predicate predicates: InternedSet<'tcx, List<Predicate<'tcx>>>, + clauses: InternedSet<'tcx, List<Clause<'tcx>>>, projs: InternedSet<'tcx, List<ProjectionKind>>, place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>, const_: InternedSet<'tcx, ConstData<'tcx>>, @@ -167,6 +169,7 @@ impl<'tcx> CtxtInterners<'tcx> { canonical_var_infos: Default::default(), predicate: Default::default(), predicates: Default::default(), + clauses: Default::default(), projs: Default::default(), place_elems: Default::default(), const_: Default::default(), @@ -1189,6 +1192,12 @@ impl<'tcx> TyCtxt<'tcx> { pub fn local_visibility(self, def_id: LocalDefId) -> Visibility { self.visibility(def_id).expect_local() } + + /// Returns the origin of the opaque type `def_id`. + #[instrument(skip(self), level = "trace", ret)] + pub fn opaque_type_origin(self, def_id: LocalDefId) -> hir::OpaqueTyOrigin { + self.hir().expect_item(def_id).expect_opaque_ty().origin + } } /// A trait implemented for all `X<'a>` types that can be safely and @@ -1533,6 +1542,7 @@ slice_interners!( canonical_var_infos: pub mk_canonical_var_infos(CanonicalVarInfo<'tcx>), poly_existential_predicates: intern_poly_existential_predicates(PolyExistentialPredicate<'tcx>), predicates: intern_predicates(Predicate<'tcx>), + clauses: intern_clauses(Clause<'tcx>), projs: pub mk_projs(ProjectionKind), place_elems: pub mk_place_elems(PlaceElem<'tcx>), bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind), @@ -1564,7 +1574,7 @@ impl<'tcx> TyCtxt<'tcx> { let future_trait = self.require_lang_item(LangItem::Future, None); self.explicit_item_bounds(def_id).skip_binder().iter().any(|&(predicate, _)| { - let ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() else { + let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() else { return false; }; trait_predicate.trait_ref.def_id == future_trait @@ -1587,7 +1597,7 @@ impl<'tcx> TyCtxt<'tcx> { let generic_predicates = self.super_predicates_of(trait_did); for (predicate, _) in generic_predicates.predicates { - if let ty::PredicateKind::Clause(ty::Clause::Trait(data)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) = predicate.kind().skip_binder() { if set.insert(data.def_id()) { @@ -2084,6 +2094,13 @@ impl<'tcx> TyCtxt<'tcx> { self.intern_predicates(preds) } + pub fn mk_clauses(self, preds: &[Clause<'tcx>]) -> &'tcx List<Clause<'tcx>> { + // FIXME consider asking the input slice to be sorted to avoid + // re-interning permutations, in which case that would be asserted + // here. + self.intern_clauses(preds) + } + pub fn mk_const_list_from_iter<I, T>(self, iter: I) -> T::Output where I: Iterator<Item = T>, @@ -2135,6 +2152,14 @@ impl<'tcx> TyCtxt<'tcx> { T::collect_and_apply(iter, |xs| self.mk_predicates(xs)) } + pub fn mk_clauses_from_iter<I, T>(self, iter: I) -> T::Output + where + I: Iterator<Item = T>, + T: CollectAndApply<Clause<'tcx>, &'tcx List<Clause<'tcx>>>, + { + T::collect_and_apply(iter, |xs| self.mk_clauses(xs)) + } + pub fn mk_type_list_from_iter<I, T>(self, iter: I) -> T::Output where I: Iterator<Item = T>, diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 684af1abdf6..cc982045c46 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -237,21 +237,24 @@ impl FlagComputation { fn add_predicate_atom(&mut self, atom: ty::PredicateKind<'_>) { match atom { - ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => { self.add_substs(trait_pred.trait_ref.substs); } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate(a, b))) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( + a, + b, + ))) => { self.add_region(a); self.add_region(b); } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( ty, region, ))) => { self.add_ty(ty); self.add_region(region); } - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { self.add_const(ct); self.add_ty(ty); } @@ -263,21 +266,21 @@ impl FlagComputation { self.add_ty(a); self.add_ty(b); } - ty::PredicateKind::Clause(ty::Clause::Projection(ty::ProjectionPredicate { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term, })) => { self.add_alias_ty(projection_ty); self.add_term(term); } - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { self.add_substs(slice::from_ref(&arg)); } ty::PredicateKind::ObjectSafe(_def_id) => {} ty::PredicateKind::ClosureKind(_def_id, substs, _kind) => { self.add_substs(substs); } - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(uv)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => { self.add_const(uv); } ty::PredicateKind::ConstEquate(expected, found) => { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index c5a306fdf1f..c1d6856d33c 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -318,7 +318,13 @@ impl<'tcx> SizeSkeleton<'tcx> { Ok(layout) => { return Ok(SizeSkeleton::Known(layout.size)); } - Err(err) => err, + Err(err @ LayoutError::Unknown(_)) => err, + // We can't extract SizeSkeleton info from other layout errors + Err( + e @ LayoutError::Cycle + | e @ LayoutError::SizeOverflow(_) + | e @ LayoutError::NormalizationFailure(..), + ) => return Err(e), }; match *ty.kind() { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 66aba98fe29..0e604fdf6f4 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -456,6 +456,11 @@ impl ty::EarlyBoundRegion { } } +/// A statement that can be proven by a trait solver. This includes things that may +/// show up in where clauses, such as trait predicates and projection predicates, +/// and also things that are emitted as part of type checking such as `ObjectSafe` +/// predicate which is emitted when a type is coerced to a trait object. +/// /// Use this rather than `PredicateKind`, whenever possible. #[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable)] #[rustc_pass_by_value] @@ -487,11 +492,11 @@ impl<'tcx> Predicate<'tcx> { let kind = self .kind() .map_bound(|kind| match kind { - PredicateKind::Clause(Clause::Trait(TraitPredicate { + PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { trait_ref, constness, polarity, - })) => Some(PredicateKind::Clause(Clause::Trait(TraitPredicate { + })) => Some(PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { trait_ref, constness, polarity: polarity.flip()?, @@ -505,10 +510,10 @@ impl<'tcx> Predicate<'tcx> { } pub fn without_const(mut self, tcx: TyCtxt<'tcx>) -> Self { - if let PredicateKind::Clause(Clause::Trait(TraitPredicate { trait_ref, constness, polarity })) = self.kind().skip_binder() + if let PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { trait_ref, constness, polarity })) = self.kind().skip_binder() && constness != BoundConstness::NotConst { - self = tcx.mk_predicate(self.kind().rebind(PredicateKind::Clause(Clause::Trait(TraitPredicate { + self = tcx.mk_predicate(self.kind().rebind(PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { trait_ref, constness: BoundConstness::NotConst, polarity, @@ -520,10 +525,10 @@ impl<'tcx> Predicate<'tcx> { #[instrument(level = "debug", skip(tcx), ret)] pub fn is_coinductive(self, tcx: TyCtxt<'tcx>) -> bool { match self.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { tcx.trait_is_coinductive(data.def_id()) } - ty::PredicateKind::Clause(ty::Clause::WellFormed(_)) => true, + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => true, _ => false, } } @@ -536,18 +541,18 @@ impl<'tcx> Predicate<'tcx> { #[inline] pub fn allow_normalization(self) -> bool { match self.kind().skip_binder() { - PredicateKind::Clause(Clause::WellFormed(_)) => false, - PredicateKind::Clause(Clause::Trait(_)) - | PredicateKind::Clause(Clause::RegionOutlives(_)) - | PredicateKind::Clause(Clause::TypeOutlives(_)) - | PredicateKind::Clause(Clause::Projection(_)) - | PredicateKind::Clause(Clause::ConstArgHasType(..)) + PredicateKind::Clause(ClauseKind::WellFormed(_)) => false, + PredicateKind::Clause(ClauseKind::Trait(_)) + | PredicateKind::Clause(ClauseKind::RegionOutlives(_)) + | PredicateKind::Clause(ClauseKind::TypeOutlives(_)) + | PredicateKind::Clause(ClauseKind::Projection(_)) + | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) | PredicateKind::AliasRelate(..) | PredicateKind::ObjectSafe(_) | PredicateKind::ClosureKind(_, _, _) | PredicateKind::Subtype(_) | PredicateKind::Coerce(_) - | PredicateKind::Clause(Clause::ConstEvaluatable(_)) + | PredicateKind::Clause(ClauseKind::ConstEvaluatable(_)) | PredicateKind::ConstEquate(_, _) | PredicateKind::Ambiguous | PredicateKind::TypeWellFormedFromEnv(_) => true, @@ -561,11 +566,67 @@ impl rustc_errors::IntoDiagnosticArg for Predicate<'_> { } } +/// A subset of predicates which can be assumed by the trait solver. They show up in +/// an item's where clauses, hence the name `Clause`, and may either be user-written +/// (such as traits) or may be inserted during lowering. +#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable)] +#[rustc_pass_by_value] +pub struct Clause<'tcx>(Interned<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>); + +impl<'tcx> Clause<'tcx> { + pub fn as_predicate(self) -> Predicate<'tcx> { + Predicate(self.0) + } + + pub fn kind(self) -> Binder<'tcx, ClauseKind<'tcx>> { + self.0.internee.map_bound(|kind| match kind { + PredicateKind::Clause(clause) => clause, + _ => unreachable!(), + }) + } + + pub fn as_trait_clause(self) -> Option<Binder<'tcx, TraitPredicate<'tcx>>> { + let clause = self.kind(); + if let ty::ClauseKind::Trait(trait_clause) = clause.skip_binder() { + Some(clause.rebind(trait_clause)) + } else { + None + } + } + + pub fn as_projection_clause(self) -> Option<Binder<'tcx, ProjectionPredicate<'tcx>>> { + let clause = self.kind(); + if let ty::ClauseKind::Projection(projection_clause) = clause.skip_binder() { + Some(clause.rebind(projection_clause)) + } else { + None + } + } + + pub fn as_type_outlives_clause(self) -> Option<Binder<'tcx, TypeOutlivesPredicate<'tcx>>> { + let clause = self.kind(); + if let ty::ClauseKind::TypeOutlives(o) = clause.skip_binder() { + Some(clause.rebind(o)) + } else { + None + } + } + + pub fn as_region_outlives_clause(self) -> Option<Binder<'tcx, RegionOutlivesPredicate<'tcx>>> { + let clause = self.kind(); + if let ty::ClauseKind::RegionOutlives(o) = clause.skip_binder() { + Some(clause.rebind(o)) + } else { + None + } + } +} + #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] /// A clause is something that can appear in where bounds or be inferred /// by implied bounds. -pub enum Clause<'tcx> { +pub enum ClauseKind<'tcx> { /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` /// would be the type parameters. @@ -592,29 +653,11 @@ pub enum Clause<'tcx> { ConstEvaluatable(ty::Const<'tcx>), } -impl<'tcx> Binder<'tcx, Clause<'tcx>> { - pub fn as_trait_clause(self) -> Option<Binder<'tcx, TraitPredicate<'tcx>>> { - if let ty::Clause::Trait(trait_clause) = self.skip_binder() { - Some(self.rebind(trait_clause)) - } else { - None - } - } - - pub fn as_projection_clause(self) -> Option<Binder<'tcx, ProjectionPredicate<'tcx>>> { - if let ty::Clause::Projection(projection_clause) = self.skip_binder() { - Some(self.rebind(projection_clause)) - } else { - None - } - } -} - #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub enum PredicateKind<'tcx> { /// Prove a clause - Clause(Clause<'tcx>), + Clause(ClauseKind<'tcx>), /// Trait must be object-safe. ObjectSafe(DefId), @@ -653,7 +696,7 @@ pub enum PredicateKind<'tcx> { /// Used for coherence to mark opaque types as possibly equal to each other but ambiguous. Ambiguous, - /// Separate from `Clause::Projection` which is used for normalization in new solver. + /// Separate from `ClauseKind::Projection` which is used for normalization in new solver. /// This predicate requires two terms to be equal to eachother. /// /// Only used for new solver @@ -687,6 +730,7 @@ pub struct CratePredicatesMap<'tcx> { /// For each struct with outlive bounds, maps to a vector of the /// predicate of its outlive bounds. If an item has no outlives /// bounds, it will have no entry. + // FIXME(clause): should this be a `Clause`? pub predicates: FxHashMap<DefId, &'tcx [(Clause<'tcx>, Span)]>, } @@ -1207,17 +1251,38 @@ impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> { } } -impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> { +impl<'tcx> ToPredicate<'tcx> for ClauseKind<'tcx> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::Clause(self))) } } -impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, Clause<'tcx>> { +impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, ClauseKind<'tcx>> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - tcx.mk_predicate(self.map_bound(|clause| ty::PredicateKind::Clause(clause))) + tcx.mk_predicate(self.map_bound(ty::PredicateKind::Clause)) + } +} + +impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> { + #[inline(always)] + fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + self.as_predicate() + } +} + +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for ClauseKind<'tcx> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + tcx.mk_predicate(Binder::dummy(ty::PredicateKind::Clause(self))).expect_clause() + } +} + +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for Binder<'tcx, ClauseKind<'tcx>> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + tcx.mk_predicate(self.map_bound(|clause| ty::PredicateKind::Clause(clause))).expect_clause() } } @@ -1228,14 +1293,11 @@ impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { } } -impl<'tcx> ToPredicate<'tcx, Binder<'tcx, Clause<'tcx>>> for TraitRef<'tcx> { +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitRef<'tcx> { #[inline(always)] - fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Binder<'tcx, Clause<'tcx>> { - Binder::dummy(Clause::Trait(TraitPredicate { - trait_ref: self, - constness: ty::BoundConstness::NotConst, - polarity: ty::ImplPolarity::Positive, - })) + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + let p: Predicate<'tcx> = self.to_predicate(tcx); + p.expect_clause() } } @@ -1247,9 +1309,9 @@ impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> { } } -impl<'tcx> ToPredicate<'tcx, Binder<'tcx, Clause<'tcx>>> for Binder<'tcx, TraitRef<'tcx>> { +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for Binder<'tcx, TraitRef<'tcx>> { #[inline(always)] - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Binder<'tcx, Clause<'tcx>> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx); pred.to_predicate(tcx) } @@ -1280,43 +1342,45 @@ impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for TraitPredicate<'tcx> impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(|p| PredicateKind::Clause(Clause::Trait(p))).to_predicate(tcx) + self.map_bound(|p| PredicateKind::Clause(ClauseKind::Trait(p))).to_predicate(tcx) } } -impl<'tcx> ToPredicate<'tcx, Binder<'tcx, Clause<'tcx>>> for PolyTraitPredicate<'tcx> { - fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Binder<'tcx, Clause<'tcx>> { - self.map_bound(|p| Clause::Trait(p)) +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyTraitPredicate<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + let p: Predicate<'tcx> = self.to_predicate(tcx); + p.expect_clause() } } impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(|p| PredicateKind::Clause(Clause::RegionOutlives(p))).to_predicate(tcx) + self.map_bound(|p| PredicateKind::Clause(ClauseKind::RegionOutlives(p))).to_predicate(tcx) } } impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(|p| PredicateKind::Clause(Clause::TypeOutlives(p))).to_predicate(tcx) + self.map_bound(|p| PredicateKind::Clause(ClauseKind::TypeOutlives(p))).to_predicate(tcx) } } impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(|p| PredicateKind::Clause(Clause::Projection(p))).to_predicate(tcx) + self.map_bound(|p| PredicateKind::Clause(ClauseKind::Projection(p))).to_predicate(tcx) } } -impl<'tcx> ToPredicate<'tcx, Binder<'tcx, Clause<'tcx>>> for PolyProjectionPredicate<'tcx> { - fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Binder<'tcx, Clause<'tcx>> { - self.map_bound(|p| Clause::Projection(p)) +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyProjectionPredicate<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + let p: Predicate<'tcx> = self.to_predicate(tcx); + p.expect_clause() } } impl<'tcx> ToPredicate<'tcx> for TraitPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - PredicateKind::Clause(Clause::Trait(self)).to_predicate(tcx) + PredicateKind::Clause(ClauseKind::Trait(self)).to_predicate(tcx) } } @@ -1324,18 +1388,18 @@ impl<'tcx> Predicate<'tcx> { pub fn to_opt_poly_trait_pred(self) -> Option<PolyTraitPredicate<'tcx>> { let predicate = self.kind(); match predicate.skip_binder() { - PredicateKind::Clause(Clause::Trait(t)) => Some(predicate.rebind(t)), - PredicateKind::Clause(Clause::Projection(..)) - | PredicateKind::Clause(Clause::ConstArgHasType(..)) + PredicateKind::Clause(ClauseKind::Trait(t)) => Some(predicate.rebind(t)), + PredicateKind::Clause(ClauseKind::Projection(..)) + | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) - | PredicateKind::Clause(Clause::RegionOutlives(..)) - | PredicateKind::Clause(Clause::WellFormed(..)) + | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) + | PredicateKind::Clause(ClauseKind::WellFormed(..)) | PredicateKind::ObjectSafe(..) | PredicateKind::ClosureKind(..) - | PredicateKind::Clause(Clause::TypeOutlives(..)) - | PredicateKind::Clause(Clause::ConstEvaluatable(..)) + | PredicateKind::Clause(ClauseKind::TypeOutlives(..)) + | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) | PredicateKind::ConstEquate(..) | PredicateKind::Ambiguous | PredicateKind::TypeWellFormedFromEnv(..) => None, @@ -1345,18 +1409,18 @@ impl<'tcx> Predicate<'tcx> { pub fn to_opt_poly_projection_pred(self) -> Option<PolyProjectionPredicate<'tcx>> { let predicate = self.kind(); match predicate.skip_binder() { - PredicateKind::Clause(Clause::Projection(t)) => Some(predicate.rebind(t)), - PredicateKind::Clause(Clause::Trait(..)) - | PredicateKind::Clause(Clause::ConstArgHasType(..)) + PredicateKind::Clause(ClauseKind::Projection(t)) => Some(predicate.rebind(t)), + PredicateKind::Clause(ClauseKind::Trait(..)) + | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) - | PredicateKind::Clause(Clause::RegionOutlives(..)) - | PredicateKind::Clause(Clause::WellFormed(..)) + | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) + | PredicateKind::Clause(ClauseKind::WellFormed(..)) | PredicateKind::ObjectSafe(..) | PredicateKind::ClosureKind(..) - | PredicateKind::Clause(Clause::TypeOutlives(..)) - | PredicateKind::Clause(Clause::ConstEvaluatable(..)) + | PredicateKind::Clause(ClauseKind::TypeOutlives(..)) + | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) | PredicateKind::ConstEquate(..) | PredicateKind::Ambiguous | PredicateKind::TypeWellFormedFromEnv(..) => None, @@ -1366,36 +1430,38 @@ impl<'tcx> Predicate<'tcx> { pub fn to_opt_type_outlives(self) -> Option<PolyTypeOutlivesPredicate<'tcx>> { let predicate = self.kind(); match predicate.skip_binder() { - PredicateKind::Clause(Clause::TypeOutlives(data)) => Some(predicate.rebind(data)), - PredicateKind::Clause(Clause::Trait(..)) - | PredicateKind::Clause(Clause::ConstArgHasType(..)) - | PredicateKind::Clause(Clause::Projection(..)) + PredicateKind::Clause(ClauseKind::TypeOutlives(data)) => Some(predicate.rebind(data)), + PredicateKind::Clause(ClauseKind::Trait(..)) + | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) + | PredicateKind::Clause(ClauseKind::Projection(..)) | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) - | PredicateKind::Clause(Clause::RegionOutlives(..)) - | PredicateKind::Clause(Clause::WellFormed(..)) + | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) + | PredicateKind::Clause(ClauseKind::WellFormed(..)) | PredicateKind::ObjectSafe(..) | PredicateKind::ClosureKind(..) - | PredicateKind::Clause(Clause::ConstEvaluatable(..)) + | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) | PredicateKind::ConstEquate(..) | PredicateKind::Ambiguous | PredicateKind::TypeWellFormedFromEnv(..) => None, } } - pub fn as_clause(self) -> Option<Binder<'tcx, Clause<'tcx>>> { - let predicate = self.kind(); - match predicate.skip_binder() { - PredicateKind::Clause(clause) => Some(predicate.rebind(clause)), - PredicateKind::AliasRelate(..) - | PredicateKind::Subtype(..) - | PredicateKind::Coerce(..) - | PredicateKind::ObjectSafe(..) - | PredicateKind::ClosureKind(..) - | PredicateKind::ConstEquate(..) - | PredicateKind::Ambiguous - | PredicateKind::TypeWellFormedFromEnv(..) => None, + /// Matches a `PredicateKind::Clause` and turns it into a `Clause`, otherwise returns `None`. + pub fn as_clause(self) -> Option<Clause<'tcx>> { + match self.kind().skip_binder() { + PredicateKind::Clause(..) => Some(self.expect_clause()), + _ => None, + } + } + + /// Turns a predicate into a clause without checking that it is a `PredicateKind::Clause` + /// first. This will ICE when methods are called on `Clause`. + pub fn expect_clause(self) -> Clause<'tcx> { + match self.kind().skip_binder() { + PredicateKind::Clause(..) => Clause(self.0), + _ => bug!(), } } } diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 13be15269f4..cc2b26a5e14 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -129,5 +129,6 @@ parameterized_over_tcx! { ty::Const, ty::Predicate, ty::Clause, + ty::ClauseKind, ty::GeneratorDiagnosticData, } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 4bfed74f705..7afda73862d 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -928,7 +928,7 @@ pub trait PrettyPrinter<'tcx>: let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => { + ty::ClauseKind::Trait(pred) => { let trait_ref = bound_predicate.rebind(pred.trait_ref); // Don't print + Sized, but rather + ?Sized if absent. @@ -939,7 +939,7 @@ pub trait PrettyPrinter<'tcx>: self.insert_trait_and_projection(trait_ref, None, &mut traits, &mut fn_traits); } - ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => { + ty::ClauseKind::Projection(pred) => { let proj_ref = bound_predicate.rebind(pred); let trait_ref = proj_ref.required_poly_trait_ref(tcx); @@ -953,7 +953,7 @@ pub trait PrettyPrinter<'tcx>: &mut fn_traits, ); } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(outlives)) => { + ty::ClauseKind::TypeOutlives(outlives) => { lifetimes.push(outlives.1); } _ => {} @@ -2866,18 +2866,18 @@ define_print_and_forward_display! { ty::PredicateKind<'tcx> { match *self { - ty::PredicateKind::Clause(ty::Clause::Trait(ref data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(ref data)) => { p!(print(data)) } ty::PredicateKind::Subtype(predicate) => p!(print(predicate)), ty::PredicateKind::Coerce(predicate) => p!(print(predicate)), - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => p!(print(predicate)), - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => p!(print(predicate)), - ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => p!(print(predicate)), - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => p!(print(predicate)), + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => p!(print(predicate)), + ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => p!(print(predicate)), + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { p!("the constant `", print(ct), "` has type `", print(ty), "`") }, - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => p!(print(arg), " well-formed"), + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => p!(print(arg), " well-formed"), ty::PredicateKind::ObjectSafe(trait_def_id) => { p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe") } @@ -2886,7 +2886,7 @@ define_print_and_forward_display! { print_value_path(closure_def_id, &[]), write("` implements the trait `{}`", kind) ), - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(ct)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => { p!("the constant `", print(ct), "` can be evaluated") } ty::PredicateKind::ConstEquate(c1, c2) => { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index a4a2fec07ec..959bf032a83 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -173,14 +173,20 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> { impl<'tcx> fmt::Debug for ty::Clause<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self.kind()) + } +} + +impl<'tcx> fmt::Debug for ty::ClauseKind<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - ty::Clause::ConstArgHasType(ct, ty) => write!(f, "ConstArgHasType({ct:?}, {ty:?})"), - ty::Clause::Trait(ref a) => a.fmt(f), - ty::Clause::RegionOutlives(ref pair) => pair.fmt(f), - ty::Clause::TypeOutlives(ref pair) => pair.fmt(f), - ty::Clause::Projection(ref pair) => pair.fmt(f), - ty::Clause::WellFormed(ref data) => write!(f, "WellFormed({:?})", data), - ty::Clause::ConstEvaluatable(ct) => { + ty::ClauseKind::ConstArgHasType(ct, ty) => write!(f, "ConstArgHasType({ct:?}, {ty:?})"), + ty::ClauseKind::Trait(ref a) => a.fmt(f), + ty::ClauseKind::RegionOutlives(ref pair) => pair.fmt(f), + ty::ClauseKind::TypeOutlives(ref pair) => pair.fmt(f), + ty::ClauseKind::Projection(ref pair) => pair.fmt(f), + ty::ClauseKind::WellFormed(ref data) => write!(f, "WellFormed({:?})", data), + ty::ClauseKind::ConstEvaluatable(ct) => { write!(f, "ConstEvaluatable({ct:?})") } } @@ -654,12 +660,28 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ty::Predicate<'tcx> { } } +// FIXME(clause): This is wonky +impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ty::Clause<'tcx> { + fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( + self, + folder: &mut F, + ) -> Result<Self, F::Error> { + Ok(folder.try_fold_predicate(self.as_predicate())?.expect_clause()) + } +} + impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ty::Predicate<'tcx> { fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { visitor.visit_predicate(*self) } } +impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ty::Clause<'tcx> { + fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { + visitor.visit_predicate(self.as_predicate()) + } +} + impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Predicate<'tcx> { fn try_super_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( self, @@ -688,6 +710,15 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Predicate<'tcx>> { } } +impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Clause<'tcx>> { + fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( + self, + folder: &mut F, + ) -> Result<Self, F::Error> { + ty::util::fold_list(self, folder, |tcx, v| tcx.mk_clauses(v)) + } +} + impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> { fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( self, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 5f2f241bc0d..c0627ab5c01 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1007,7 +1007,10 @@ impl BoundVariableKind { /// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(HashStable, Lift)] -pub struct Binder<'tcx, T>(T, &'tcx List<BoundVariableKind>); +pub struct Binder<'tcx, T> { + value: T, + bound_vars: &'tcx List<BoundVariableKind>, +} impl<'tcx, T> Binder<'tcx, T> where @@ -1023,15 +1026,15 @@ where !value.has_escaping_bound_vars(), "`{value:?}` has escaping bound vars, so it cannot be wrapped in a dummy binder." ); - Binder(value, ty::List::empty()) + Binder { value, bound_vars: ty::List::empty() } } - pub fn bind_with_vars(value: T, vars: &'tcx List<BoundVariableKind>) -> Binder<'tcx, T> { + pub fn bind_with_vars(value: T, bound_vars: &'tcx List<BoundVariableKind>) -> Binder<'tcx, T> { if cfg!(debug_assertions) { - let mut validator = ValidateBoundVars::new(vars); + let mut validator = ValidateBoundVars::new(bound_vars); value.visit_with(&mut validator); } - Binder(value, vars) + Binder { value, bound_vars } } } @@ -1053,30 +1056,30 @@ impl<'tcx, T> Binder<'tcx, T> { /// - comparing the self type of a PolyTraitRef to see if it is equal to /// a type parameter `X`, since the type `X` does not reference any regions pub fn skip_binder(self) -> T { - self.0 + self.value } pub fn bound_vars(&self) -> &'tcx List<BoundVariableKind> { - self.1 + self.bound_vars } pub fn as_ref(&self) -> Binder<'tcx, &T> { - Binder(&self.0, self.1) + Binder { value: &self.value, bound_vars: self.bound_vars } } pub fn as_deref(&self) -> Binder<'tcx, &T::Target> where T: Deref, { - Binder(&self.0, self.1) + Binder { value: &self.value, bound_vars: self.bound_vars } } pub fn map_bound_ref_unchecked<F, U>(&self, f: F) -> Binder<'tcx, U> where F: FnOnce(&T) -> U, { - let value = f(&self.0); - Binder(value, self.1) + let value = f(&self.value); + Binder { value, bound_vars: self.bound_vars } } pub fn map_bound_ref<F, U: TypeVisitable<TyCtxt<'tcx>>>(&self, f: F) -> Binder<'tcx, U> @@ -1090,12 +1093,13 @@ impl<'tcx, T> Binder<'tcx, T> { where F: FnOnce(T) -> U, { - let value = f(self.0); + let Binder { value, bound_vars } = self; + let value = f(value); if cfg!(debug_assertions) { - let mut validator = ValidateBoundVars::new(self.1); + let mut validator = ValidateBoundVars::new(bound_vars); value.visit_with(&mut validator); } - Binder(value, self.1) + Binder { value, bound_vars } } pub fn try_map_bound<F, U: TypeVisitable<TyCtxt<'tcx>>, E>( @@ -1105,12 +1109,13 @@ impl<'tcx, T> Binder<'tcx, T> { where F: FnOnce(T) -> Result<U, E>, { - let value = f(self.0)?; + let Binder { value, bound_vars } = self; + let value = f(value)?; if cfg!(debug_assertions) { - let mut validator = ValidateBoundVars::new(self.1); + let mut validator = ValidateBoundVars::new(bound_vars); value.visit_with(&mut validator); } - Ok(Binder(value, self.1)) + Ok(Binder { value, bound_vars }) } /// Wraps a `value` in a binder, using the same bound variables as the @@ -1126,11 +1131,7 @@ impl<'tcx, T> Binder<'tcx, T> { where U: TypeVisitable<TyCtxt<'tcx>>, { - if cfg!(debug_assertions) { - let mut validator = ValidateBoundVars::new(self.bound_vars()); - value.visit_with(&mut validator); - } - Binder(value, self.1) + Binder::bind_with_vars(value, self.bound_vars) } /// Unwraps and returns the value within, but only if it contains @@ -1147,7 +1148,7 @@ impl<'tcx, T> Binder<'tcx, T> { where T: TypeVisitable<TyCtxt<'tcx>>, { - if self.0.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) } + if self.value.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) } } /// Splits the contents into two things that share the same binder @@ -1160,22 +1161,23 @@ impl<'tcx, T> Binder<'tcx, T> { where F: FnOnce(T) -> (U, V), { - let (u, v) = f(self.0); - (Binder(u, self.1), Binder(v, self.1)) + let Binder { value, bound_vars } = self; + let (u, v) = f(value); + (Binder { value: u, bound_vars }, Binder { value: v, bound_vars }) } } impl<'tcx, T> Binder<'tcx, Option<T>> { pub fn transpose(self) -> Option<Binder<'tcx, T>> { - let bound_vars = self.1; - self.0.map(|v| Binder(v, bound_vars)) + let Binder { value, bound_vars } = self; + value.map(|value| Binder { value, bound_vars }) } } impl<'tcx, T: IntoIterator> Binder<'tcx, T> { pub fn iter(self) -> impl Iterator<Item = ty::Binder<'tcx, T::Item>> { - let bound_vars = self.1; - self.0.into_iter().map(|v| Binder(v, bound_vars)) + let Binder { value, bound_vars } = self; + value.into_iter().map(|value| Binder { value, bound_vars }) } } @@ -1184,7 +1186,7 @@ where T: IntoDiagnosticArg, { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - self.0.into_diagnostic_arg() + self.value.into_diagnostic_arg() } } @@ -1582,7 +1584,7 @@ pub struct EarlyBoundRegion { impl fmt::Debug for EarlyBoundRegion { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}, {}", self.index, self.name) + write!(f, "{:?}, {}, {}", self.def_id, self.index, self.name) } } diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 8685a22d9ca..111b1d009b3 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -538,19 +538,21 @@ impl<'tcx, T: TypeVisitable<TyCtxt<'tcx>>> TypeVisitable<TyCtxt<'tcx>> for &'tcx /// [`subst_identity`](EarlyBinder::subst_identity) or [`skip_binder`](EarlyBinder::skip_binder). #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Encodable, Decodable, HashStable)] -pub struct EarlyBinder<T>(T); +pub struct EarlyBinder<T> { + value: T, +} /// For early binders, you should first call `subst` before using any visitors. impl<'tcx, T> !TypeFoldable<TyCtxt<'tcx>> for ty::EarlyBinder<T> {} impl<'tcx, T> !TypeVisitable<TyCtxt<'tcx>> for ty::EarlyBinder<T> {} impl<T> EarlyBinder<T> { - pub fn bind(inner: T) -> EarlyBinder<T> { - EarlyBinder(inner) + pub fn bind(value: T) -> EarlyBinder<T> { + EarlyBinder { value } } pub fn as_ref(&self) -> EarlyBinder<&T> { - EarlyBinder(&self.0) + EarlyBinder { value: &self.value } } pub fn map_bound_ref<F, U>(&self, f: F) -> EarlyBinder<U> @@ -564,20 +566,20 @@ impl<T> EarlyBinder<T> { where F: FnOnce(T) -> U, { - let value = f(self.0); - EarlyBinder(value) + let value = f(self.value); + EarlyBinder { value } } pub fn try_map_bound<F, U, E>(self, f: F) -> Result<EarlyBinder<U>, E> where F: FnOnce(T) -> Result<U, E>, { - let value = f(self.0)?; - Ok(EarlyBinder(value)) + let value = f(self.value)?; + Ok(EarlyBinder { value }) } pub fn rebind<U>(&self, value: U) -> EarlyBinder<U> { - EarlyBinder(value) + EarlyBinder { value } } /// Skips the binder and returns the "bound" value. @@ -592,19 +594,20 @@ impl<T> EarlyBinder<T> { /// See also [`Binder::skip_binder`](super::Binder::skip_binder), which is /// the analogous operation on [`super::Binder`]. pub fn skip_binder(self) -> T { - self.0 + self.value } } impl<T> EarlyBinder<Option<T>> { pub fn transpose(self) -> Option<EarlyBinder<T>> { - self.0.map(|v| EarlyBinder(v)) + self.value.map(|value| EarlyBinder { value }) } } impl<T, U> EarlyBinder<(T, U)> { pub fn transpose_tuple2(self) -> (EarlyBinder<T>, EarlyBinder<U>) { - (EarlyBinder(self.0.0), EarlyBinder(self.0.1)) + let EarlyBinder { value: (lhs, rhs) } = self; + (EarlyBinder { value: lhs }, EarlyBinder { value: rhs }) } } @@ -617,13 +620,13 @@ where tcx: TyCtxt<'tcx>, substs: &'s [GenericArg<'tcx>], ) -> SubstIter<'s, 'tcx, I> { - SubstIter { it: self.0.into_iter(), tcx, substs } + SubstIter { it: self.value.into_iter(), tcx, substs } } /// Similar to [`subst_identity`](EarlyBinder::subst_identity), /// but on an iterator of `TypeFoldable` values. pub fn subst_identity_iter(self) -> I::IntoIter { - self.0.into_iter() + self.value.into_iter() } } @@ -640,7 +643,7 @@ where type Item = I::Item; fn next(&mut self) -> Option<Self::Item> { - Some(EarlyBinder(self.it.next()?).subst(self.tcx, self.substs)) + Some(EarlyBinder { value: self.it.next()? }.subst(self.tcx, self.substs)) } fn size_hint(&self) -> (usize, Option<usize>) { @@ -654,7 +657,7 @@ where I::Item: TypeFoldable<TyCtxt<'tcx>>, { fn next_back(&mut self) -> Option<Self::Item> { - Some(EarlyBinder(self.it.next_back()?).subst(self.tcx, self.substs)) + Some(EarlyBinder { value: self.it.next_back()? }.subst(self.tcx, self.substs)) } } @@ -675,13 +678,13 @@ where tcx: TyCtxt<'tcx>, substs: &'s [GenericArg<'tcx>], ) -> SubstIterCopied<'s, 'tcx, I> { - SubstIterCopied { it: self.0.into_iter(), tcx, substs } + SubstIterCopied { it: self.value.into_iter(), tcx, substs } } /// Similar to [`subst_identity`](EarlyBinder::subst_identity), /// but on an iterator of values that deref to a `TypeFoldable`. pub fn subst_identity_iter_copied(self) -> impl Iterator<Item = <I::Item as Deref>::Target> { - self.0.into_iter().map(|v| *v) + self.value.into_iter().map(|v| *v) } } @@ -699,7 +702,7 @@ where type Item = <I::Item as Deref>::Target; fn next(&mut self) -> Option<Self::Item> { - Some(EarlyBinder(*self.it.next()?).subst(self.tcx, self.substs)) + self.it.next().map(|value| EarlyBinder { value: *value }.subst(self.tcx, self.substs)) } fn size_hint(&self) -> (usize, Option<usize>) { @@ -714,7 +717,7 @@ where <I::Item as Deref>::Target: Copy + TypeFoldable<TyCtxt<'tcx>>, { fn next_back(&mut self) -> Option<Self::Item> { - Some(EarlyBinder(*self.it.next_back()?).subst(self.tcx, self.substs)) + self.it.next_back().map(|value| EarlyBinder { value: *value }.subst(self.tcx, self.substs)) } } @@ -732,7 +735,7 @@ pub struct EarlyBinderIter<T> { impl<T: IntoIterator> EarlyBinder<T> { pub fn transpose_iter(self) -> EarlyBinderIter<T::IntoIter> { - EarlyBinderIter { t: self.0.into_iter() } + EarlyBinderIter { t: self.value.into_iter() } } } @@ -740,7 +743,7 @@ impl<T: Iterator> Iterator for EarlyBinderIter<T> { type Item = EarlyBinder<T::Item>; fn next(&mut self) -> Option<Self::Item> { - self.t.next().map(|i| EarlyBinder(i)) + self.t.next().map(|value| EarlyBinder { value }) } fn size_hint(&self) -> (usize, Option<usize>) { @@ -751,7 +754,7 @@ impl<T: Iterator> Iterator for EarlyBinderIter<T> { impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> ty::EarlyBinder<T> { pub fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> T { let mut folder = SubstFolder { tcx, substs, binders_passed: 0 }; - self.0.fold_with(&mut folder) + self.value.fold_with(&mut folder) } /// Makes the identity substitution `T0 => T0, ..., TN => TN`. @@ -763,12 +766,12 @@ impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> ty::EarlyBinder<T> { /// - Inside of the body of `foo`, we treat `T` as a placeholder by calling /// `subst_identity` to discharge the `EarlyBinder`. pub fn subst_identity(self) -> T { - self.0 + self.value } /// Returns the inner value, but only if it contains no bound vars. pub fn no_bound_vars(self) -> Option<T> { - if !self.0.has_param() { Some(self.0) } else { None } + if !self.value.has_param() { Some(self.value) } else { None } } } diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index e61037e5ea8..98c70e330f1 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -52,6 +52,16 @@ pub struct TraitDef { /// List of functions from `#[rustc_must_implement_one_of]` attribute one of which /// must be implemented. pub must_implement_one_of: Option<Box<[Ident]>>, + + /// Whether to add a builtin `dyn Trait: Trait` implementation. + /// This is enabled for all traits except ones marked with + /// `#[rustc_deny_explicit_impl(implement_via_object = false)]`. + pub implement_via_object: bool, + + /// Whether a trait is fully built-in, and any implementation is disallowed. + /// This only applies to built-in traits, and is marked via + /// `#[rustc_deny_explicit_impl(implement_via_object = ...)]`. + pub deny_explicit_impl: bool, } /// Whether this trait is treated specially by the standard library diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index c9f69c37782..fcd624b3fef 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1,7 +1,6 @@ //! Miscellaneous type-system utilities that are too small to deserve their own modules. use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use crate::mir; use crate::query::Providers; use crate::ty::layout::IntegerExt; use crate::ty::{ @@ -17,7 +16,6 @@ use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_index::bit_set::GrowableBitSet; -use rustc_index::{Idx, IndexVec}; use rustc_macros::HashStable; use rustc_session::Limit; use rustc_span::sym; @@ -738,80 +736,6 @@ impl<'tcx> TyCtxt<'tcx> { if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } } - /// Returns names of captured upvars for closures and generators. - /// - /// Here are some examples: - /// - `name__field1__field2` when the upvar is captured by value. - /// - `_ref__name__field` when the upvar is captured by reference. - /// - /// For generators this only contains upvars that are shared by all states. - pub fn closure_saved_names_of_captured_variables( - self, - def_id: DefId, - ) -> SmallVec<[String; 16]> { - let body = self.optimized_mir(def_id); - - body.var_debug_info - .iter() - .filter_map(|var| { - let is_ref = match var.value { - mir::VarDebugInfoContents::Place(place) - if place.local == mir::Local::new(1) => - { - // The projection is either `[.., Field, Deref]` or `[.., Field]`. It - // implies whether the variable is captured by value or by reference. - matches!(place.projection.last().unwrap(), mir::ProjectionElem::Deref) - } - _ => return None, - }; - let prefix = if is_ref { "_ref__" } else { "" }; - Some(prefix.to_owned() + var.name.as_str()) - }) - .collect() - } - - // FIXME(eddyb) maybe precompute this? Right now it's computed once - // per generator monomorphization, but it doesn't depend on substs. - pub fn generator_layout_and_saved_local_names( - self, - def_id: DefId, - ) -> ( - &'tcx ty::GeneratorLayout<'tcx>, - IndexVec<mir::GeneratorSavedLocal, Option<rustc_span::Symbol>>, - ) { - let tcx = self; - let body = tcx.optimized_mir(def_id); - let generator_layout = body.generator_layout().unwrap(); - let mut generator_saved_local_names = - IndexVec::from_elem(None, &generator_layout.field_tys); - - let state_arg = mir::Local::new(1); - for var in &body.var_debug_info { - let mir::VarDebugInfoContents::Place(place) = &var.value else { continue }; - if place.local != state_arg { - continue; - } - match place.projection[..] { - [ - // Deref of the `Pin<&mut Self>` state argument. - mir::ProjectionElem::Field(..), - mir::ProjectionElem::Deref, - // Field of a variant of the state. - mir::ProjectionElem::Downcast(_, variant), - mir::ProjectionElem::Field(field, _), - ] => { - let name = &mut generator_saved_local_names - [generator_layout.variant_fields[variant][field]]; - if name.is_none() { - name.replace(var.name); - } - } - _ => {} - } - } - (generator_layout, generator_saved_local_names) - } - /// Query and get an English description for the item's kind. pub fn def_descr(self, def_id: DefId) -> &'static str { self.def_kind_descr(self.def_kind(def_id), def_id) @@ -972,7 +896,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for OpaqueTypeExpander<'tcx> { fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { if let ty::PredicateKind::Clause(clause) = p.kind().skip_binder() - && let ty::Clause::Projection(projection_pred) = clause + && let ty::ClauseKind::Projection(projection_pred) = clause { p.kind() .rebind(ty::ProjectionPredicate { diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index ebf830cb9c1..4cb9d7babe1 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -128,7 +128,9 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { destination, target: Some(target), unwind: UnwindAction::Continue, - from_hir_call: *from_hir_call, + call_source: if *from_hir_call { CallSource::Normal } else { + CallSource::OverloadedOperator + }, fn_span: *fn_span, }) }, diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 3742d640e3b..ec00f9a96be 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -173,7 +173,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination: storage, target: Some(success), unwind: UnwindAction::Continue, - from_hir_call: false, + call_source: CallSource::Misc, fn_span: expr_span, }, ); @@ -442,7 +442,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match upvar.kind { ExprKind::Borrow { borrow_kind: - BorrowKind::Mut { allow_two_phase_borrow: false }, + BorrowKind::Mut { kind: MutBorrowKind::Default }, arg, } => unpack!( block = this.limit_capture_mutability( @@ -795,8 +795,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; let borrow_kind = match mutability { - Mutability::Not => BorrowKind::Unique, - Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false }, + Mutability::Not => BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, + Mutability::Mut => BorrowKind::Mut { kind: MutBorrowKind::Default }, }; let arg_place = arg_place_builder.to_place(this); diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 29ff916d2cc..731f3996244 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -277,7 +277,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .ty .is_inhabited_from(this.tcx, this.parent_module, this.param_env) .then_some(success), - from_hir_call, + call_source: if from_hir_call { + CallSource::Normal + } else { + CallSource::OverloadedOperator + }, fn_span, }, ); diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index dbdb5b4a9a1..f431023f2b6 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -264,7 +264,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination: ref_str, target: Some(eq_block), unwind: UnwindAction::Continue, - from_hir_call: false, + call_source: CallSource::Misc, fn_span: source_info.span } ); @@ -496,7 +496,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination: eq_result, target: Some(eq_block), unwind: UnwindAction::Continue, - from_hir_call: false, + call_source: CallSource::MatchCmp, fn_span: source_info.span, }, ); diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 7f0c1d53f72..49cbe3e2c9b 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -36,6 +36,22 @@ pub(crate) fn mir_built( tcx.alloc_steal_mir(mir_build(tcx, def)) } +pub(crate) fn closure_saved_names_of_captured_variables<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> IndexVec<FieldIdx, Symbol> { + tcx.closure_captures(def_id) + .iter() + .map(|captured_place| { + let name = captured_place.to_symbol(); + match captured_place.info.capture_kind { + ty::UpvarCapture::ByValue => name, + ty::UpvarCapture::ByRef(..) => Symbol::intern(&format!("_ref__{name}")), + } + }) + .collect() +} + /// Construct the MIR for a given `DefId`. fn mir_build(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> { // Ensure unsafeck and abstract const building is ran before we steal the THIR. diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 0506f2bf238..4f3a574031d 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -254,7 +254,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { ); }; match borrow_kind { - BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => { + BorrowKind::Shallow | BorrowKind::Shared => { if !ty.is_freeze(self.tcx, self.param_env) { self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField); } @@ -440,7 +440,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { visit::walk_expr(&mut visitor, expr); if visitor.found { match borrow_kind { - BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique + BorrowKind::Shallow | BorrowKind::Shared if !self.thir[arg].ty.is_freeze(self.tcx, self.param_env) => { self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField) @@ -448,7 +448,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { BorrowKind::Mut { .. } => { self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField) } - BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => {} + BorrowKind::Shallow | BorrowKind::Shared => {} } } } diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 0eaab9b5703..4fdc3178c4e 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -33,6 +33,8 @@ pub fn provide(providers: &mut Providers) { providers.check_match = thir::pattern::check_match; providers.lit_to_const = thir::constant::lit_to_const; providers.mir_built = build::mir_built; + providers.closure_saved_names_of_captured_variables = + build::closure_saved_names_of_captured_variables; providers.thir_check_unsafety = check_unsafety::thir_check_unsafety; providers.thir_body = thir::cx::thir_body; providers.thir_tree = thir::print::thir_tree; diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index b20495d602e..7f0c2e9ca3f 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -1095,8 +1095,12 @@ impl<'tcx> Cx<'tcx> { ty::UpvarCapture::ByRef(upvar_borrow) => { let borrow_kind = match upvar_borrow { ty::BorrowKind::ImmBorrow => BorrowKind::Shared, - ty::BorrowKind::UniqueImmBorrow => BorrowKind::Unique, - ty::BorrowKind::MutBorrow => BorrowKind::Mut { allow_two_phase_borrow: false }, + ty::BorrowKind::UniqueImmBorrow => { + BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } + } + ty::BorrowKind::MutBorrow => { + BorrowKind::Mut { kind: mir::MutBorrowKind::Default } + } }; Expr { temp_lifetime, @@ -1132,9 +1136,9 @@ impl ToBorrowKind for AutoBorrowMutability { use rustc_middle::ty::adjustment::AllowTwoPhase; match *self { AutoBorrowMutability::Mut { allow_two_phase_borrow } => BorrowKind::Mut { - allow_two_phase_borrow: match allow_two_phase_borrow { - AllowTwoPhase::Yes => true, - AllowTwoPhase::No => false, + kind: match allow_two_phase_borrow { + AllowTwoPhase::Yes => mir::MutBorrowKind::TwoPhaseBorrow, + AllowTwoPhase::No => mir::MutBorrowKind::Default, }, }, AutoBorrowMutability::Not => BorrowKind::Shared, @@ -1145,7 +1149,7 @@ impl ToBorrowKind for AutoBorrowMutability { impl ToBorrowKind for hir::Mutability { fn to_borrow_kind(&self) -> BorrowKind { match *self { - hir::Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false }, + hir::Mutability::Mut => BorrowKind::Mut { kind: mir::MutBorrowKind::Default }, hir::Mutability::Not => BorrowKind::Shared, } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 7976b148f75..a2e00d3bfc5 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -359,6 +359,15 @@ impl<'tcx> ConstToPat<'tcx> { def.non_enum_variant().fields.iter().map(|field| field.ty(self.tcx(), substs)), ))?, }, + ty::Slice(elem_ty) => PatKind::Slice { + prefix: cv + .unwrap_branch() + .iter() + .map(|val| self.recur(*val, *elem_ty, false)) + .collect::<Result<_, _>>()?, + slice: None, + suffix: Box::new([]), + }, ty::Array(elem_ty, _) => PatKind::Array { prefix: cv .unwrap_branch() @@ -372,58 +381,6 @@ impl<'tcx> ConstToPat<'tcx> { // `&str` is represented as a valtree, let's keep using this // optimization for now. ty::Str => PatKind::Constant { value: mir::ConstantKind::Ty(tcx.mk_const(cv, ty)) }, - // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when - // matching against references, you can only use byte string literals. - // The typechecker has a special case for byte string literals, by treating them - // as slices. This means we turn `&[T; N]` constants into slice patterns, which - // has no negative effects on pattern matching, even if we're actually matching on - // arrays. - ty::Array(elem_ty, _) if !self.treat_byte_string_as_slice => { - let old = self.behind_reference.replace(true); - // References have the same valtree representation as their pointee. - let array = cv; - let val = PatKind::Deref { - subpattern: Box::new(Pat { - kind: PatKind::Array { - prefix: array.unwrap_branch() - .iter() - .map(|val| self.recur(*val, elem_ty, false)) - .collect::<Result<_, _>>()?, - slice: None, - suffix: Box::new([]), - }, - span, - ty: tcx.mk_slice(elem_ty), - }), - }; - self.behind_reference.set(old); - val - } - ty::Array(elem_ty, _) | - // Cannot merge this with the catch all branch below, because the `const_deref` - // changes the type from slice to array, we need to keep the original type in the - // pattern. - ty::Slice(elem_ty) => { - let old = self.behind_reference.replace(true); - // References have the same valtree representation as their pointee. - let array = cv; - let val = PatKind::Deref { - subpattern: Box::new(Pat { - kind: PatKind::Slice { - prefix: array.unwrap_branch() - .iter() - .map(|val| self.recur(*val, elem_ty, false)) - .collect::<Result<_, _>>()?, - slice: None, - suffix: Box::new([]), - }, - span, - ty: tcx.mk_slice(elem_ty), - }), - }; - self.behind_reference.set(old); - val - } // Backwards compatibility hack: support references to non-structural types, // but hard error if we aren't behind a double reference. We could just use // the fallback code path below, but that would allow *more* of this fishy @@ -431,11 +388,9 @@ impl<'tcx> ConstToPat<'tcx> { // instead of a hard error. ty::Adt(_, _) if !self.type_marked_structural(*pointee_ty) => { if self.behind_reference.get() { - if !self.saw_const_match_error.get() - && !self.saw_const_match_lint.get() - { - self.saw_const_match_lint.set(true); - tcx.emit_spanned_lint( + if !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() { + self.saw_const_match_lint.set(true); + tcx.emit_spanned_lint( lint::builtin::INDIRECT_STRUCTURAL_MATCH, self.id, span, @@ -456,7 +411,7 @@ impl<'tcx> ConstToPat<'tcx> { // convert the dereferenced constant to a pattern that is the sub-pattern of the // deref pattern. _ => { - if !pointee_ty.is_sized(tcx, param_env) { + if !pointee_ty.is_sized(tcx, param_env) && !pointee_ty.is_slice() { let err = UnsizedPattern { span, non_sm_ty: *pointee_ty }; tcx.sess.emit_err(err); @@ -464,8 +419,20 @@ impl<'tcx> ConstToPat<'tcx> { PatKind::Wild } else { let old = self.behind_reference.replace(true); + // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when + // matching against references, you can only use byte string literals. + // The typechecker has a special case for byte string literals, by treating them + // as slices. This means we turn `&[T; N]` constants into slice patterns, which + // has no negative effects on pattern matching, even if we're actually matching on + // arrays. + let pointee_ty = match *pointee_ty.kind() { + ty::Array(elem_ty, _) if self.treat_byte_string_as_slice => { + tcx.mk_slice(elem_ty) + } + _ => *pointee_ty, + }; // References have the same valtree representation as their pointee. - let subpattern = self.recur(cv, *pointee_ty, false)?; + let subpattern = self.recur(cv, pointee_ty, false)?; self.behind_reference.set(old); PatKind::Deref { subpattern } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 8eeb055ed82..c30c4b65939 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -287,7 +287,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { ty::BindByValue(mutbl) => (mutbl, BindingMode::ByValue), ty::BindByReference(hir::Mutability::Mut) => ( Mutability::Not, - BindingMode::ByRef(BorrowKind::Mut { allow_two_phase_borrow: false }), + BindingMode::ByRef(BorrowKind::Mut { kind: mir::MutBorrowKind::Default }), ), ty::BindByReference(hir::Mutability::Not) => { (Mutability::Not, BindingMode::ByRef(BorrowKind::Shared)) diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index 4fc45eaf522..c0102b15a16 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -638,7 +638,7 @@ where Place::from(ref_place), Rvalue::Ref( tcx.lifetimes.re_erased, - BorrowKind::Mut { allow_two_phase_borrow: false }, + BorrowKind::Mut { kind: MutBorrowKind::Default }, self.place, ), )], @@ -654,7 +654,7 @@ where destination: unit_temp, target: Some(succ), unwind: unwind.into_action(), - from_hir_call: true, + call_source: CallSource::Misc, fn_span: self.source_info.span, }, source_info: self.source_info, diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 0c379288a09..804b44a6bf0 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -502,15 +502,7 @@ impl Direction for Forward { propagate(target, exit_state); } - Call { - unwind, - destination, - target, - func: _, - args: _, - from_hir_call: _, - fn_span: _, - } => { + Call { unwind, destination, target, func: _, args: _, call_source: _, fn_span: _ } => { if let UnwindAction::Cleanup(unwind) = unwind { propagate(unwind, exit_state); } diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index 4bdfa35fc70..c755d7588c2 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -287,9 +287,11 @@ where let mut results = Results { analysis, entry_sets, _marker: PhantomData }; - let res = write_graphviz_results(tcx, body, &mut results, pass_name); - if let Err(e) = res { - error!("Failed to write graphviz dataflow results: {}", e); + if tcx.sess.opts.unstable_opts.dump_mir_dataflow { + let res = write_graphviz_results(tcx, &body, &mut results, pass_name); + if let Err(e) = res { + error!("Failed to write graphviz dataflow results: {}", e); + } } results @@ -299,7 +301,7 @@ where // Graphviz /// Writes a DOT file containing the results of a dataflow analysis if the user requested it via -/// `rustc_mir` attributes. +/// `rustc_mir` attributes and `-Z dump-mir-dataflow`. fn write_graphviz_results<'tcx, A>( tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>, @@ -328,9 +330,7 @@ where io::BufWriter::new(fs::File::create(&path)?) } - None if tcx.sess.opts.unstable_opts.dump_mir_dataflow - && dump_enabled(tcx, A::NAME, def_id) => - { + None if dump_enabled(tcx, A::NAME, def_id) => { create_dump_file(tcx, ".dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)? } diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index 45c2fe55aca..cb0ec144ef0 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -40,7 +40,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> { destination: dummy_place.clone(), target: Some(mir::START_BLOCK), unwind: mir::UnwindAction::Continue, - from_hir_call: false, + call_source: mir::CallSource::Misc, fn_span: DUMMY_SP, }, ); @@ -54,7 +54,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> { destination: dummy_place.clone(), target: Some(mir::START_BLOCK), unwind: mir::UnwindAction::Continue, - from_hir_call: false, + call_source: mir::CallSource::Misc, fn_span: DUMMY_SP, }, ); diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 096bc0acfcc..fe9631653ea 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -399,7 +399,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { destination, target, unwind: _, - from_hir_call: _, + call_source: _, fn_span: _, } => { self.gather_operand(func); diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index 187d38b385b..d9e7339f1b2 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -28,6 +28,7 @@ fn may_contain_reference<'tcx>(ty: Ty<'tcx>, depth: u32, tcx: TyCtxt<'tcx>) -> b // References ty::Ref(..) => true, ty::Adt(..) if ty.is_box() => true, + ty::Adt(adt, _) if Some(adt.did()) == tcx.lang_items().ptr_unique() => true, // Compound types: recurse ty::Array(ty, _) | ty::Slice(ty) => { // This does not branch so we keep the depth the same. diff --git a/compiler/rustc_mir_transform/src/const_goto.rs b/compiler/rustc_mir_transform/src/const_goto.rs index 024bea62098..e175f22d7a9 100644 --- a/compiler/rustc_mir_transform/src/const_goto.rs +++ b/compiler/rustc_mir_transform/src/const_goto.rs @@ -28,7 +28,9 @@ pub struct ConstGoto; impl<'tcx> MirPass<'tcx> for ConstGoto { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.mir_opt_level() >= 2 + // This pass participates in some as-of-yet untested unsoundness found + // in https://github.com/rust-lang/rust/issues/112460 + sess.mir_opt_level() >= 2 && sess.opts.unstable_opts.unsound_mir_opts } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index 90b58933df7..25891d3ca0f 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -140,7 +140,7 @@ impl<'tcx> MockBlocks<'tcx> { destination: self.dummy_place.clone(), target: Some(TEMP_BLOCK), unwind: UnwindAction::Continue, - from_hir_call: false, + call_source: CallSource::Misc, fn_span: DUMMY_SP, }, ) diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index b1c9c4acc40..502f367dcb6 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -34,7 +34,7 @@ impl<'tcx> Visitor<'tcx> for FunctionItemRefChecker<'_, 'tcx> { destination: _, target: _, unwind: _, - from_hir_call: _, + call_source: _, fn_span: _, } = &terminator.kind { @@ -105,7 +105,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { /// If the given predicate is the trait `fmt::Pointer`, returns the bound parameter type. fn is_pointer_trait(&self, bound: &PredicateKind<'tcx>) -> Option<Ty<'tcx>> { - if let ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) = bound { + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) = bound { self.tcx .is_diagnostic_item(sym::Pointer, predicate.def_id()) .then(|| predicate.trait_ref.self_ty()) diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index fe3f8ed047a..029fb2e9ba0 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -230,7 +230,7 @@ struct TransformVisitor<'tcx> { // Mapping from Local to (type of local, generator struct index) // FIXME(eddyb) This should use `IndexVec<Local, Option<_>>`. - remap: FxHashMap<Local, (Ty<'tcx>, VariantIdx, usize)>, + remap: FxHashMap<Local, (Ty<'tcx>, VariantIdx, FieldIdx)>, // A map from a suspension point in a block to the locals which have live storage at that point storage_liveness: IndexVec<BasicBlock, Option<BitSet<Local>>>, @@ -295,11 +295,11 @@ impl<'tcx> TransformVisitor<'tcx> { } // Create a Place referencing a generator struct field - fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> { + fn make_field(&self, variant_index: VariantIdx, idx: FieldIdx, ty: Ty<'tcx>) -> Place<'tcx> { let self_place = Place::from(SELF_ARG); let base = self.tcx.mk_place_downcast_unnamed(self_place, variant_index); let mut projection = base.projection.to_vec(); - projection.push(ProjectionElem::Field(FieldIdx::new(idx), ty)); + projection.push(ProjectionElem::Field(idx, ty)); Place { local: base.local, projection: self.tcx.mk_place_elems(&projection) } } @@ -904,7 +904,7 @@ fn compute_layout<'tcx>( liveness: LivenessInfo, body: &Body<'tcx>, ) -> ( - FxHashMap<Local, (Ty<'tcx>, VariantIdx, usize)>, + FxHashMap<Local, (Ty<'tcx>, VariantIdx, FieldIdx)>, GeneratorLayout<'tcx>, IndexVec<BasicBlock, Option<BitSet<Local>>>, ) { @@ -982,6 +982,7 @@ fn compute_layout<'tcx>( // just use the first one here. That's fine; fields do not move // around inside generators, so it doesn't matter which variant // index we access them by. + let idx = FieldIdx::from_usize(idx); remap.entry(locals[saved_local]).or_insert((tys[saved_local].ty, variant_index, idx)); } variant_fields.push(fields); @@ -990,8 +991,23 @@ fn compute_layout<'tcx>( debug!("generator variant_fields = {:?}", variant_fields); debug!("generator storage_conflicts = {:#?}", storage_conflicts); - let layout = - GeneratorLayout { field_tys: tys, variant_fields, variant_source_info, storage_conflicts }; + let mut field_names = IndexVec::from_elem(None, &tys); + for var in &body.var_debug_info { + let VarDebugInfoContents::Place(place) = &var.value else { continue }; + let Some(local) = place.as_local() else { continue }; + let Some(&(_, variant, field)) = remap.get(&local) else { continue }; + + let saved_local = variant_fields[variant][field]; + field_names.get_or_insert_with(saved_local, || var.name); + } + + let layout = GeneratorLayout { + field_tys: tys, + field_names, + variant_fields, + variant_source_info, + storage_conflicts, + }; debug!(?layout); (remap, layout, storage_liveness) @@ -1692,7 +1708,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> { destination, target: Some(_), unwind: _, - from_hir_call: _, + call_source: _, fn_span: _, } => { self.check_assigned_place(*destination, |this| { @@ -1808,7 +1824,7 @@ fn check_must_not_suspend_ty<'tcx>( let mut has_emitted = false; for &(predicate, _) in tcx.explicit_item_bounds(def).skip_binder() { // We only look at the `DefId`, so it is safe to skip the binder here. - if let ty::PredicateKind::Clause(ty::Clause::Trait(ref poly_trait_predicate)) = + if let ty::ClauseKind::Trait(ref poly_trait_predicate) = predicate.kind().skip_binder() { let def_id = poly_trait_predicate.trait_ref.def_id; diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index b28fed7159f..703824f5bda 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -522,7 +522,7 @@ impl<'tcx> Inliner<'tcx> { trace!("creating temp for return destination"); let dest = Rvalue::Ref( self.tcx.lifetimes.re_erased, - BorrowKind::Mut { allow_two_phase_borrow: false }, + BorrowKind::Mut { kind: MutBorrowKind::Default }, destination, ); let dest_ty = dest.ty(caller_body, self.tcx); diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 9c8c0ea0be0..fa8257cf984 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -30,8 +30,8 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_index::IndexVec; use rustc_middle::mir::visit::Visitor as _; use rustc_middle::mir::{ - traversal, AnalysisPhase, Body, ClearCrossCrate, ConstQualifs, Constant, LocalDecl, MirPass, - MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo, + traversal, AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstQualifs, Constant, LocalDecl, + MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo, Statement, StatementKind, TerminatorKind, START_BLOCK, }; use rustc_middle::query::Providers; @@ -189,7 +189,7 @@ fn remap_mir_for_const_eval_select<'tcx>( }; method(place) }).collect(); - terminator.kind = TerminatorKind::Call { func, args: arguments, destination, target, unwind, from_hir_call: false, fn_span }; + terminator.kind = TerminatorKind::Call { func, args: arguments, destination, target, unwind, call_source: CallSource::Misc, fn_span }; } _ => {} } diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 3a7d58f7125..ce98e9b0c84 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -85,8 +85,13 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul + | sym::unchecked_add + | sym::unchecked_sub + | sym::unchecked_mul | sym::unchecked_div - | sym::unchecked_rem => { + | sym::unchecked_rem + | sym::unchecked_shl + | sym::unchecked_shr => { let target = target.unwrap(); let lhs; let rhs; @@ -99,8 +104,13 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { sym::wrapping_add => BinOp::Add, sym::wrapping_sub => BinOp::Sub, sym::wrapping_mul => BinOp::Mul, + sym::unchecked_add => BinOp::AddUnchecked, + sym::unchecked_sub => BinOp::SubUnchecked, + sym::unchecked_mul => BinOp::MulUnchecked, sym::unchecked_div => BinOp::Div, sym::unchecked_rem => BinOp::Rem, + sym::unchecked_shl => BinOp::ShlUnchecked, + sym::unchecked_shr => BinOp::ShrUnchecked, _ => bug!("unexpected intrinsic"), }; block.statements.push(Statement { diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs index 6e40dfa0d13..b7cc0db9559 100644 --- a/compiler/rustc_mir_transform/src/lower_slice_len.rs +++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs @@ -54,7 +54,7 @@ fn lower_slice_len_call<'tcx>( args, destination, target: Some(bb), - from_hir_call: true, + call_source: CallSource::Normal, .. } => { // some heuristics for fast rejection diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs index f35a5fb4276..1d8e54cdca0 100644 --- a/compiler/rustc_mir_transform/src/separate_const_switch.rs +++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs @@ -46,7 +46,9 @@ pub struct SeparateConstSwitch; impl<'tcx> MirPass<'tcx> for SeparateConstSwitch { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.mir_opt_level() >= 2 + // This pass participates in some as-of-yet untested unsoundness found + // in https://github.com/rust-lang/rust/issues/112460 + sess.mir_opt_level() >= 2 && sess.opts.unstable_opts.unsound_mir_opts } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 5f12f1937c0..2ae5ec4d9e6 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -188,7 +188,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>) // has been put into the body. let reborrow = Rvalue::Ref( tcx.lifetimes.re_erased, - BorrowKind::Mut { allow_two_phase_borrow: false }, + BorrowKind::Mut { kind: MutBorrowKind::Default }, tcx.mk_place_deref(dropee_ptr), ); let ref_ty = reborrow.ty(body.local_decls(), tcx); @@ -500,7 +500,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { destination: dest, target: Some(next), unwind: UnwindAction::Cleanup(cleanup), - from_hir_call: true, + call_source: CallSource::Normal, fn_span: self.span, }, false, @@ -712,7 +712,7 @@ fn build_call_shim<'tcx>( ) .immutable(), ); - let borrow_kind = BorrowKind::Mut { allow_two_phase_borrow: false }; + let borrow_kind = BorrowKind::Mut { kind: MutBorrowKind::Default }; statements.push(Statement { source_info, kind: StatementKind::Assign(Box::new(( @@ -789,7 +789,7 @@ fn build_call_shim<'tcx>( } else { UnwindAction::Continue }, - from_hir_call: true, + call_source: CallSource::Misc, fn_span: span, }, false, diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 531644f0b84..97e3748b8b8 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -125,7 +125,7 @@ struct PartitioningCx<'a, 'tcx> { usage_map: &'a UsageMap<'tcx>, } -struct PlacedRootMonoItems<'tcx> { +struct PlacedMonoItems<'tcx> { /// The codegen units, sorted by name to make things deterministic. codegen_units: Vec<CodegenUnit<'tcx>>, @@ -150,18 +150,13 @@ where let cx = &PartitioningCx { tcx, usage_map }; - // In the first step, we place all regular monomorphizations into their - // respective 'home' codegen unit. Regular monomorphizations are all - // functions and statics defined in the local crate. - let PlacedRootMonoItems { mut codegen_units, internalization_candidates, unique_inlined_stats } = { - let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots"); - let mut placed = place_root_mono_items(cx, mono_items); + // Place all mono items into a codegen unit. `place_mono_items` is + // responsible for initializing the CGU size estimates. + let PlacedMonoItems { mut codegen_units, internalization_candidates, unique_inlined_stats } = { + let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_items"); + let placed = place_mono_items(cx, mono_items); - for cgu in &mut placed.codegen_units { - cgu.create_size_estimate(tcx); - } - - debug_dump(tcx, "ROOTS", &placed.codegen_units, placed.unique_inlined_stats); + debug_dump(tcx, "PLACE", &placed.codegen_units, placed.unique_inlined_stats); placed }; @@ -175,23 +170,8 @@ where debug_dump(tcx, "MERGE", &codegen_units, unique_inlined_stats); } - // In the next step, we use the inlining map to determine which additional - // monomorphizations have to go into each codegen unit. These additional - // monomorphizations can be drop-glue, functions from external crates, and - // local functions the definition of which is marked with `#[inline]`. - { - let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items"); - place_inlined_mono_items(cx, &mut codegen_units); - - for cgu in &mut codegen_units { - cgu.create_size_estimate(tcx); - } - - debug_dump(tcx, "INLINE", &codegen_units, unique_inlined_stats); - } - - // Next we try to make as many symbols "internal" as possible, so LLVM has - // more freedom to optimize. + // Make as many symbols "internal" as possible, so LLVM has more freedom to + // optimize. if !tcx.sess.link_dead_code() { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols"); internalize_symbols(cx, &mut codegen_units, internalization_candidates); @@ -212,10 +192,7 @@ where codegen_units } -fn place_root_mono_items<'tcx, I>( - cx: &PartitioningCx<'_, 'tcx>, - mono_items: I, -) -> PlacedRootMonoItems<'tcx> +fn place_mono_items<'tcx, I>(cx: &PartitioningCx<'_, 'tcx>, mono_items: I) -> PlacedMonoItems<'tcx> where I: Iterator<Item = MonoItem<'tcx>>, { @@ -236,6 +213,8 @@ where let mut num_unique_inlined_items = 0; let mut unique_inlined_items_size = 0; for mono_item in mono_items { + // Handle only root items directly here. Inlined items are handled at + // the bottom of the loop based on reachability. match mono_item.instantiation_mode(cx.tcx) { InstantiationMode::GloballyShared { .. } => {} InstantiationMode::LocalCopy => { @@ -248,7 +227,7 @@ where let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item); let is_volatile = is_incremental_build && mono_item.is_generic_fn(); - let codegen_unit_name = match characteristic_def_id { + let cgu_name = match characteristic_def_id { Some(def_id) => compute_codegen_unit_name( cx.tcx, cgu_name_builder, @@ -259,9 +238,7 @@ where None => fallback_cgu_name(cgu_name_builder), }; - let codegen_unit = codegen_units - .entry(codegen_unit_name) - .or_insert_with(|| CodegenUnit::new(codegen_unit_name)); + let cgu = codegen_units.entry(cgu_name).or_insert_with(|| CodegenUnit::new(cgu_name)); let mut can_be_internalized = true; let (linkage, visibility) = mono_item_linkage_and_visibility( @@ -274,23 +251,56 @@ where internalization_candidates.insert(mono_item); } - codegen_unit.items_mut().insert(mono_item, (linkage, visibility)); + cgu.items_mut().insert(mono_item, (linkage, visibility)); + + // Get all inlined items that are reachable from `mono_item` without + // going via another root item. This includes drop-glue, functions from + // external crates, and local functions the definition of which is + // marked with `#[inline]`. + let mut reachable_inlined_items = FxHashSet::default(); + get_reachable_inlined_items(cx.tcx, mono_item, cx.usage_map, &mut reachable_inlined_items); + + // Add those inlined items. It's possible an inlined item is reachable + // from multiple root items within a CGU, which is fine, it just means + // the `insert` will be a no-op. + for inlined_item in reachable_inlined_items { + // This is a CGU-private copy. + cgu.items_mut().insert(inlined_item, (Linkage::Internal, Visibility::Default)); + } } // Always ensure we have at least one CGU; otherwise, if we have a // crate with just types (for example), we could wind up with no CGU. if codegen_units.is_empty() { - let codegen_unit_name = fallback_cgu_name(cgu_name_builder); - codegen_units.insert(codegen_unit_name, CodegenUnit::new(codegen_unit_name)); + let cgu_name = fallback_cgu_name(cgu_name_builder); + codegen_units.insert(cgu_name, CodegenUnit::new(cgu_name)); } let mut codegen_units: Vec<_> = codegen_units.into_values().collect(); codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); - PlacedRootMonoItems { + for cgu in codegen_units.iter_mut() { + cgu.compute_size_estimate(cx.tcx); + } + + return PlacedMonoItems { codegen_units, internalization_candidates, unique_inlined_stats: (num_unique_inlined_items, unique_inlined_items_size), + }; + + fn get_reachable_inlined_items<'tcx>( + tcx: TyCtxt<'tcx>, + item: MonoItem<'tcx>, + usage_map: &UsageMap<'tcx>, + visited: &mut FxHashSet<MonoItem<'tcx>>, + ) { + usage_map.for_each_inlined_used_item(tcx, item, |inlined_item| { + let is_new = visited.insert(inlined_item); + if is_new { + get_reachable_inlined_items(tcx, inlined_item, usage_map, visited); + } + }); } } @@ -314,7 +324,7 @@ fn merge_codegen_units<'tcx>( // worse generated code. So we don't allow CGUs smaller than this (unless // there is just one CGU, of course). Note that CGU sizes of 100,000+ are // common in larger programs, so this isn't all that large. - const NON_INCR_MIN_CGU_SIZE: usize = 1000; + const NON_INCR_MIN_CGU_SIZE: usize = 1800; // Repeatedly merge the two smallest codegen units as long as: // - we have more CGUs than the upper limit, or @@ -338,9 +348,11 @@ fn merge_codegen_units<'tcx>( let mut smallest = codegen_units.pop().unwrap(); let second_smallest = codegen_units.last_mut().unwrap(); - // Move the mono-items from `smallest` to `second_smallest` - second_smallest.modify_size_estimate(smallest.size_estimate()); + // Move the items from `smallest` to `second_smallest`. Some of them + // may be duplicate inlined items, in which case the destination CGU is + // unaffected. Recalculate size estimates afterwards. second_smallest.items_mut().extend(smallest.items_mut().drain()); + second_smallest.compute_size_estimate(cx.tcx); // Record that `second_smallest` now contains all the stuff that was // in `smallest` before. @@ -406,43 +418,6 @@ fn merge_codegen_units<'tcx>( codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); } -fn place_inlined_mono_items<'tcx>( - cx: &PartitioningCx<'_, 'tcx>, - codegen_units: &mut [CodegenUnit<'tcx>], -) { - for cgu in codegen_units.iter_mut() { - // Collect all inlined items that need to be available in this codegen unit. - let mut reachable_inlined_items = FxHashSet::default(); - for root in cgu.items().keys() { - // Get all inlined items that are reachable from it without going - // via another root item. - get_reachable_inlined_items(cx.tcx, *root, cx.usage_map, &mut reachable_inlined_items); - } - - // Add all monomorphizations that are not already there. - for inlined_item in reachable_inlined_items { - assert!(!cgu.items().contains_key(&inlined_item)); - - // This is a CGU-private copy. - cgu.items_mut().insert(inlined_item, (Linkage::Internal, Visibility::Default)); - } - } - - fn get_reachable_inlined_items<'tcx>( - tcx: TyCtxt<'tcx>, - item: MonoItem<'tcx>, - usage_map: &UsageMap<'tcx>, - visited: &mut FxHashSet<MonoItem<'tcx>>, - ) { - usage_map.for_each_inlined_used_item(tcx, item, |inlined_item| { - let is_new = visited.insert(inlined_item); - if is_new { - get_reachable_inlined_items(tcx, inlined_item, usage_map, visited); - } - }); - } -} - fn internalize_symbols<'tcx>( cx: &PartitioningCx<'_, 'tcx>, codegen_units: &mut [CodegenUnit<'tcx>], diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 57202ac9c6e..5f2f86e8113 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1436,6 +1436,8 @@ impl<'a> Parser<'a> { self.parse_expr_yield() } else if self.is_do_yeet() { self.parse_expr_yeet() + } else if self.eat_keyword(kw::Become) { + self.parse_expr_become() } else if self.check_keyword(kw::Let) { self.parse_expr_let() } else if self.eat_keyword(kw::Underscore) { @@ -1752,6 +1754,16 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr) } + /// Parse `"become" expr`, with `"become"` token already eaten. + fn parse_expr_become(&mut self) -> PResult<'a, P<Expr>> { + let lo = self.prev_token.span; + let kind = ExprKind::Become(self.parse_expr()?); + let span = lo.to(self.prev_token.span); + self.sess.gated_spans.gate(sym::explicit_tail_calls, span); + let expr = self.mk_expr(span, kind); + self.maybe_recover_from_bad_qpath(expr) + } + /// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten. /// If the label is followed immediately by a `:` token, the label and `:` are /// parsed as part of the expression (i.e. a labeled loop). The language team has diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index e76f1614b93..a607e483c97 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -102,9 +102,6 @@ passes_const_impl_const_trait = const `impl`s must be for traits marked with `#[const_trait]` .note = this trait must be annotated with `#[const_trait]` -passes_const_trait = - attribute should be applied to a trait - passes_continue_labeled_block = `continue` pointing to a labeled block .label = labeled blocks cannot be `continue`'d diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c35c7da2664..073760f394e 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -110,9 +110,6 @@ impl CheckAttrVisitor<'_> { sym::no_coverage => self.check_no_coverage(hir_id, attr, span, target), sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target), sym::marker => self.check_marker(hir_id, attr, span, target), - sym::rustc_must_implement_one_of => { - self.check_rustc_must_implement_one_of(attr, span, target) - } sym::target_feature => self.check_target_feature(hir_id, attr, span, target), sym::thread_local => self.check_thread_local(attr, span, target), sym::track_caller => { @@ -159,12 +156,14 @@ impl CheckAttrVisitor<'_> { | sym::rustc_dirty | sym::rustc_if_this_changed | sym::rustc_then_this_would_need => self.check_rustc_dirty_clean(&attr), - sym::rustc_coinductive => self.check_rustc_coinductive(&attr, span, target), + sym::rustc_coinductive + | sym::rustc_must_implement_one_of + | sym::rustc_deny_explicit_impl + | sym::const_trait => self.check_must_be_applied_to_trait(&attr, span, target), sym::cmse_nonsecure_entry => { self.check_cmse_nonsecure_entry(hir_id, attr, span, target) } sym::collapse_debuginfo => self.check_collapse_debuginfo(attr, span, target), - sym::const_trait => self.check_const_trait(attr, span, target), sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target), sym::must_use => self.check_must_use(hir_id, &attr, target), sym::rustc_pass_by_value => self.check_pass_by_value(&attr, span, target), @@ -567,25 +566,6 @@ impl CheckAttrVisitor<'_> { } } - /// Checks if the `#[rustc_must_implement_one_of]` attribute on a `target` is valid. Returns `true` if valid. - fn check_rustc_must_implement_one_of( - &self, - attr: &Attribute, - span: Span, - target: Target, - ) -> bool { - match target { - Target::Trait => true, - _ => { - self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToTrait { - attr_span: attr.span, - defn_span: span, - }); - false - } - } - } - /// Checks if the `#[target_feature]` attribute on `item` is valid. Returns `true` if valid. fn check_target_feature( &self, @@ -1591,8 +1571,8 @@ impl CheckAttrVisitor<'_> { } } - /// Checks if the `#[rustc_coinductive]` attribute is applied to a trait. - fn check_rustc_coinductive(&self, attr: &Attribute, span: Span, target: Target) -> bool { + /// Checks if the attribute is applied to a trait. + fn check_must_be_applied_to_trait(&self, attr: &Attribute, span: Span, target: Target) -> bool { match target { Target::Trait => true, _ => { @@ -1986,17 +1966,6 @@ impl CheckAttrVisitor<'_> { } } - /// `#[const_trait]` only applies to traits. - fn check_const_trait(&self, attr: &Attribute, _span: Span, target: Target) -> bool { - match target { - Target::Trait => true, - _ => { - self.tcx.sess.emit_err(errors::ConstTrait { attr_span: attr.span }); - false - } - } - } - fn check_stability_promotable(&self, attr: &Attribute, _span: Span, target: Target) -> bool { match target { Target::Expression => { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index ae624dbc9c9..7890c93d5ff 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -611,13 +611,6 @@ pub struct RustcStdInternalSymbol { } #[derive(Diagnostic)] -#[diag(passes_const_trait)] -pub struct ConstTrait { - #[primary_span] - pub attr_span: Span, -} - -#[derive(Diagnostic)] #[diag(passes_link_ordinal)] pub struct LinkOrdinal { #[primary_span] diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index dc5e454074d..90809270118 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -569,7 +569,8 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let, If, While, ForLoop, Loop, Match, Closure, Block, Async, Await, TryBlock, Assign, AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret, - InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, IncludedBytes, Err + InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, + Become, IncludedBytes, Err ] ); ast_visit::walk_expr(self, e) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 620aef9883b..8a848e5db62 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -114,6 +114,12 @@ trait DefIdVisitor<'tcx> { ) -> ControlFlow<Self::BreakTy> { self.skeleton().visit_predicates(predicates) } + fn visit_clauses( + &mut self, + predicates: &[(ty::Clause<'tcx>, Span)], + ) -> ControlFlow<Self::BreakTy> { + self.skeleton().visit_clauses(predicates) + } } struct DefIdVisitorSkeleton<'v, 'tcx, V: ?Sized> { @@ -159,40 +165,23 @@ where } } - fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::BreakTy> { - match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { - trait_ref, - constness: _, - polarity: _, - })) => self.visit_trait(trait_ref), - ty::PredicateKind::Clause(ty::Clause::Projection(ty::ProjectionPredicate { - projection_ty, - term, - })) => { + fn visit_clause(&mut self, clause: ty::Clause<'tcx>) -> ControlFlow<V::BreakTy> { + match clause.kind().skip_binder() { + ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, constness: _, polarity: _ }) => { + self.visit_trait(trait_ref) + } + ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => { term.visit_with(self)?; self.visit_projection_ty(projection_ty) } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( - ty, - _region, - ))) => ty.visit_with(self), - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) => ControlFlow::Continue(()), - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => ty.visit_with(self), + ty::ClauseKind::RegionOutlives(..) => ControlFlow::Continue(()), + ty::ClauseKind::ConstArgHasType(ct, ty) => { ct.visit_with(self)?; ty.visit_with(self) } - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(ct)) => ct.visit_with(self), - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => arg.visit_with(self), - - ty::PredicateKind::ObjectSafe(_) - | ty::PredicateKind::ClosureKind(_, _, _) - | ty::PredicateKind::Subtype(_) - | ty::PredicateKind::Coerce(_) - | ty::PredicateKind::ConstEquate(_, _) - | ty::PredicateKind::TypeWellFormedFromEnv(_) - | ty::PredicateKind::Ambiguous - | ty::PredicateKind::AliasRelate(..) => bug!("unexpected predicate: {:?}", predicate), + ty::ClauseKind::ConstEvaluatable(ct) => ct.visit_with(self), + ty::ClauseKind::WellFormed(arg) => arg.visit_with(self), } } @@ -201,7 +190,16 @@ where predicates: ty::GenericPredicates<'tcx>, ) -> ControlFlow<V::BreakTy> { let ty::GenericPredicates { parent: _, predicates } = predicates; - predicates.iter().try_for_each(|&(predicate, _span)| self.visit_predicate(predicate)) + predicates.iter().try_for_each(|&(predicate, _span)| { + let clause = predicate + .as_clause() + .unwrap_or_else(|| bug!("unexpected predicate: {:?}", predicate)); + self.visit_clause(clause) + }) + } + + fn visit_clauses(&mut self, clauses: &[(ty::Clause<'tcx>, Span)]) -> ControlFlow<V::BreakTy> { + clauses.iter().try_for_each(|&(clause, _span)| self.visit_clause(clause)) } } @@ -305,10 +303,7 @@ where // through the trait list (default type visitor doesn't visit those traits). // All traits in the list are considered the "primary" part of the type // and are visited by shallow visitors. - self.visit_predicates(ty::GenericPredicates { - parent: None, - predicates: tcx.explicit_item_bounds(def_id).skip_binder(), - })?; + self.visit_clauses(tcx.explicit_item_bounds(def_id).skip_binder())?; } } // These types don't have their own def-ids (but may have subcomponents @@ -1269,14 +1264,14 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { self.tcx.types.never, ); - for (pred, _) in bounds.predicates() { - match pred.skip_binder() { - ty::Clause::Trait(trait_predicate) => { + for (clause, _) in bounds.clauses() { + match clause.kind().skip_binder() { + ty::ClauseKind::Trait(trait_predicate) => { if self.visit_trait(trait_predicate.trait_ref).is_break() { return; } } - ty::Clause::Projection(proj_predicate) => { + ty::ClauseKind::Projection(proj_predicate) => { let term = self.visit(proj_predicate.term); if term.is_break() || self.visit_projection_ty(proj_predicate.projection_ty).is_break() @@ -1812,10 +1807,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { fn bounds(&mut self) -> &mut Self { self.in_primary_interface = false; - self.visit_predicates(ty::GenericPredicates { - parent: None, - predicates: self.tcx.explicit_item_bounds(self.item_def_id).skip_binder(), - }); + self.visit_clauses(self.tcx.explicit_item_bounds(self.item_def_id).skip_binder()); self } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 244f0e84b43..cb0df1d1b82 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -531,6 +531,8 @@ macro_rules! define_queries { key: queries::$name::Key<'tcx>, mode: QueryMode, ) -> Option<Erase<queries::$name::Value<'tcx>>> { + #[cfg(debug_assertions)] + let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered(); get_query_incr( QueryType::config(tcx), QueryCtxt::new(tcx), @@ -571,10 +573,16 @@ macro_rules! define_queries { cache_on_disk: |tcx, key| ::rustc_middle::query::cached::$name(tcx, key), execute_query: |tcx, key| erase(tcx.$name(key)), compute: |tcx, key| { + #[cfg(debug_assertions)] + let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered(); __rust_begin_short_backtrace(|| queries::$name::provided_to_erased( tcx, - call_provider!([$($modifiers)*][tcx, $name, key]) + { + let ret = call_provider!([$($modifiers)*][tcx, $name, key]); + tracing::trace!(?ret); + ret + } ) ) }, diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 539b88aa9d3..60b6d74da7b 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -5,6 +5,9 @@ resolve_add_as_non_derive = add as non-Derive macro `#[{$macro_path}]` +resolve_added_macro_use = + have you added the `#[macro_use]` on the module/import? + resolve_ampersand_used_without_explicit_lifetime_name = `&` without an explicit lifetime name cannot be used here .note = explicit lifetime name needed here @@ -45,9 +48,18 @@ resolve_cannot_capture_dynamic_environment_in_fn_item = can't capture dynamic environment in a fn item .help = use the `|| {"{"} ... {"}"}` closure form instead +resolve_cannot_find_ident_in_this_scope = + cannot find {$expected} `{$ident}` in this scope + resolve_cannot_use_self_type_here = can't use `Self` here +resolve_change_import_binding = + you can use `as` to change the binding name of the import + +resolve_consider_adding_a_derive = + consider adding a derive + resolve_const_not_member_of_trait = const `{$const_}` is not a member of trait `{$trait_}` .label = not a member of trait `{$trait_}` @@ -74,6 +86,9 @@ resolve_expected_found = expected module, found {$res} `{$path_str}` .label = not a module +resolve_explicit_unsafe_traits = + unsafe traits like `{$ident}` should be implemented explicitly + resolve_forward_declared_generic_param = generic parameters with a default cannot use forward declared identifiers .label = defaulted generic parameters cannot be forward declared @@ -96,6 +111,9 @@ resolve_ident_bound_more_than_once_in_same_pattern = resolve_imported_crate = `$crate` may not be imported +resolve_imports_cannot_refer_to = + imports cannot refer to {$what} + resolve_indeterminate = cannot determine resolution for the visibility diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index e42b2df1a5a..d77fb922e84 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -30,6 +30,10 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Span, SyntaxContext}; use thin_vec::ThinVec; +use crate::errors::{ + AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive, + ExplicitUnsafeTraits, +}; use crate::imports::{Import, ImportKind}; use crate::late::{PatternSource, Rib}; use crate::path_names_to_string; @@ -99,6 +103,7 @@ pub(crate) struct ImportSuggestion { pub descr: &'static str, pub path: Path, pub accessible: bool, + pub via_import: bool, /// An extra note that should be issued if this item is suggested pub note: Option<String>, } @@ -136,9 +141,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } let mut reported_spans = FxHashSet::default(); - for error in &self.privacy_errors { + for error in std::mem::take(&mut self.privacy_errors) { if reported_spans.insert(error.dedup_span) { - self.report_privacy_error(error); + self.report_privacy_error(&error); } } } @@ -376,16 +381,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { _ => unreachable!(), } - let rename_msg = "you can use `as` to change the binding name of the import"; if let Some(suggestion) = suggestion { - err.span_suggestion( - binding_span, - rename_msg, - suggestion, - Applicability::MaybeIncorrect, - ); + err.subdiagnostic(ChangeImportBindingSuggestion { span: binding_span, suggestion }); } else { - err.span_label(binding_span, rename_msg); + err.subdiagnostic(ChangeImportBinding { span: binding_span }); } } @@ -1258,6 +1257,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { path, accessible: child_accessible, note, + via_import, }); } } @@ -1382,12 +1382,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ); if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) { - let msg = format!("unsafe traits like `{}` should be implemented explicitly", ident); - err.span_note(ident.span, msg); + err.subdiagnostic(ExplicitUnsafeTraits { span: ident.span, ident }); return; } if self.macro_names.contains(&ident.normalize_to_macros_2_0()) { - err.help("have you added the `#[macro_use]` on the module/import?"); + err.subdiagnostic(AddedMacroUse); return; } if ident.name == kw::Default @@ -1396,14 +1395,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let span = self.def_span(def_id); let source_map = self.tcx.sess.source_map(); let head_span = source_map.guess_head_span(span); - if let Ok(head) = source_map.span_to_snippet(head_span) { - err.span_suggestion(head_span, "consider adding a derive", format!("#[derive(Default)]\n{head}"), Applicability::MaybeIncorrect); - } else { - err.span_help( - head_span, - "consider adding `#[derive(Default)]` to this enum", - ); - } + err.subdiagnostic(ConsiderAddingADerive { + span: head_span.shrink_to_lo(), + suggestion: format!("#[derive(Default)]\n") + }); } for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] { if let Ok(binding) = self.early_resolve_ident_in_lexical_scope( @@ -1616,8 +1611,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { None } - fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) { - let PrivacyError { ident, binding, .. } = *privacy_error; + fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'a>) { + let PrivacyError { ident, binding, outermost_res, parent_scope, dedup_span } = + *privacy_error; let res = binding.res(); let ctor_fields_span = self.ctor_fields_span(binding); @@ -1634,6 +1630,33 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { struct_span_err!(self.tcx.sess, ident.span, E0603, "{} `{}` is private", descr, ident); err.span_label(ident.span, format!("private {}", descr)); + if let Some((this_res, outer_ident)) = outermost_res { + let import_suggestions = self.lookup_import_candidates( + outer_ident, + this_res.ns().unwrap_or(Namespace::TypeNS), + &parent_scope, + &|res: Res| res == this_res, + ); + let point_to_def = !show_candidates( + self.tcx, + &mut err, + Some(dedup_span.until(outer_ident.span.shrink_to_hi())), + &import_suggestions, + Instead::Yes, + FoundUse::Yes, + DiagnosticMode::Import, + vec![], + "", + ); + // If we suggest importing a public re-export, don't point at the definition. + if point_to_def && ident.span != outer_ident.span { + err.span_label( + outer_ident.span, + format!("{} `{outer_ident}` is not publicly re-exported", this_res.descr()), + ); + } + } + let mut non_exhaustive = None; // If an ADT is foreign and marked as `non_exhaustive`, then that's // probably why we have the privacy error. @@ -2462,7 +2485,8 @@ pub(crate) fn import_candidates( /// When an entity with a given name is not available in scope, we search for /// entities with that name in all crates. This method allows outputting the -/// results of this search in a programmer-friendly way +/// results of this search in a programmer-friendly way. If any entities are +/// found and suggested, returns `true`, otherwise returns `false`. fn show_candidates( tcx: TyCtxt<'_>, err: &mut Diagnostic, @@ -2474,19 +2498,19 @@ fn show_candidates( mode: DiagnosticMode, path: Vec<Segment>, append: &str, -) { +) -> bool { if candidates.is_empty() { - return; + return false; } - let mut accessible_path_strings: Vec<(String, &str, Option<DefId>, &Option<String>)> = + let mut accessible_path_strings: Vec<(String, &str, Option<DefId>, &Option<String>, bool)> = Vec::new(); - let mut inaccessible_path_strings: Vec<(String, &str, Option<DefId>, &Option<String>)> = + let mut inaccessible_path_strings: Vec<(String, &str, Option<DefId>, &Option<String>, bool)> = Vec::new(); candidates.iter().for_each(|c| { (if c.accessible { &mut accessible_path_strings } else { &mut inaccessible_path_strings }) - .push((path_names_to_string(&c.path), c.descr, c.did, &c.note)) + .push((path_names_to_string(&c.path), c.descr, c.did, &c.note, c.via_import)) }); // we want consistent results across executions, but candidates are produced @@ -2500,20 +2524,25 @@ fn show_candidates( } if !accessible_path_strings.is_empty() { - let (determiner, kind, name) = if accessible_path_strings.len() == 1 { - ("this", accessible_path_strings[0].1, format!(" `{}`", accessible_path_strings[0].0)) - } else { - ("one of these", "items", String::new()) - }; + let (determiner, kind, name, through) = + if let [(name, descr, _, _, via_import)] = &accessible_path_strings[..] { + ( + "this", + *descr, + format!(" `{name}`"), + if *via_import { " through its public re-export" } else { "" }, + ) + } else { + ("one of these", "items", String::new(), "") + }; let instead = if let Instead::Yes = instead { " instead" } else { "" }; let mut msg = if let DiagnosticMode::Pattern = mode { format!( - "if you meant to match on {}{}{}, use the full path in the pattern", - kind, instead, name + "if you meant to match on {kind}{instead}{name}, use the full path in the pattern", ) } else { - format!("consider importing {} {}{}", determiner, kind, instead) + format!("consider importing {determiner} {kind}{through}{instead}") }; for note in accessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) { @@ -2529,7 +2558,7 @@ fn show_candidates( accessible_path_strings.into_iter().map(|a| a.0), Applicability::MaybeIncorrect, ); - return; + return true; } DiagnosticMode::Import => ("", ""), DiagnosticMode::Normal => ("use ", ";\n"), @@ -2570,6 +2599,7 @@ fn show_candidates( err.help(msg); } + true } else if !matches!(mode, DiagnosticMode::Import) { assert!(!inaccessible_path_strings.is_empty()); @@ -2578,13 +2608,9 @@ fn show_candidates( } else { "" }; - if inaccessible_path_strings.len() == 1 { - let (name, descr, def_id, note) = &inaccessible_path_strings[0]; + if let [(name, descr, def_id, note, _)] = &inaccessible_path_strings[..] { let msg = format!( - "{}{} `{}`{} exists but is inaccessible", - prefix, - descr, - name, + "{prefix}{descr} `{name}`{} exists but is inaccessible", if let DiagnosticMode::Pattern = mode { ", which" } else { "" } ); @@ -2601,11 +2627,11 @@ fn show_candidates( err.note(note.to_string()); } } else { - let (_, descr_first, _, _) = &inaccessible_path_strings[0]; + let (_, descr_first, _, _, _) = &inaccessible_path_strings[0]; let descr = if inaccessible_path_strings .iter() .skip(1) - .all(|(_, descr, _, _)| descr == descr_first) + .all(|(_, descr, _, _, _)| descr == descr_first) { descr_first } else { @@ -2618,7 +2644,7 @@ fn show_candidates( let mut has_colon = false; let mut spans = Vec::new(); - for (name, _, def_id, _) in &inaccessible_path_strings { + for (name, _, def_id, _, _) in &inaccessible_path_strings { if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) { let span = tcx.source_span(local_def_id); let span = tcx.sess.source_map().guess_head_span(span); @@ -2644,6 +2670,9 @@ fn show_candidates( err.span_note(multi_span, msg); } + true + } else { + false } } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index e88cbb955b5..93b626c7794 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -586,3 +586,63 @@ pub(crate) enum ParamKindInEnumDiscriminant { #[note(resolve_lifetime_param_in_enum_discriminant)] Lifetime, } + +#[derive(Subdiagnostic)] +#[label(resolve_change_import_binding)] +pub(crate) struct ChangeImportBinding { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion( + resolve_change_import_binding, + code = "{suggestion}", + applicability = "maybe-incorrect" +)] +pub(crate) struct ChangeImportBindingSuggestion { + #[primary_span] + pub(crate) span: Span, + pub(crate) suggestion: String, +} + +#[derive(Diagnostic)] +#[diag(resolve_imports_cannot_refer_to)] +pub(crate) struct ImportsCannotReferTo<'a> { + #[primary_span] + pub(crate) span: Span, + pub(crate) what: &'a str, +} + +#[derive(Diagnostic)] +#[diag(resolve_cannot_find_ident_in_this_scope)] +pub(crate) struct CannotFindIdentInThisScope<'a> { + #[primary_span] + pub(crate) span: Span, + pub(crate) expected: &'a str, + pub(crate) ident: Ident, +} + +#[derive(Subdiagnostic)] +#[note(resolve_explicit_unsafe_traits)] +pub(crate) struct ExplicitUnsafeTraits { + #[primary_span] + pub(crate) span: Span, + pub(crate) ident: Ident, +} + +#[derive(Subdiagnostic)] +#[help(resolve_added_macro_use)] +pub(crate) struct AddedMacroUse; + +#[derive(Subdiagnostic)] +#[suggestion( + resolve_consider_adding_a_derive, + code = "{suggestion}", + applicability = "maybe-incorrect" +)] +pub(crate) struct ConsiderAddingADerive { + #[primary_span] + pub(crate) span: Span, + pub(crate) suggestion: String, +} diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index ec0a8535e71..e5fa062967f 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -893,6 +893,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ident, binding, dedup_span: path_span, + outermost_res: None, + parent_scope: *parent_scope, }); } else { return Err((Determined, Weak::No)); @@ -1369,6 +1371,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let mut allow_super = true; let mut second_binding = None; + // We'll provide more context to the privacy errors later, up to `len`. + let privacy_errors_len = self.privacy_errors.len(); + for (segment_idx, &Segment { ident, id, .. }) in path.iter().enumerate() { debug!("resolve_path ident {} {:?} {:?}", segment_idx, ident, id); let record_segment_res = |this: &mut Self, res| { @@ -1459,66 +1464,61 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }); } - enum FindBindingResult<'a> { - Binding(Result<&'a NameBinding<'a>, Determinacy>), - Res(Res), - } - let find_binding_in_ns = |this: &mut Self, ns| { - let binding = if let Some(module) = module { - this.resolve_ident_in_module( - module, - ident, - ns, - parent_scope, - finalize, - ignore_binding, - ) - } else if let Some(ribs) = ribs - && let Some(TypeNS | ValueNS) = opt_ns - { - match this.resolve_ident_in_lexical_scope( - ident, - ns, - parent_scope, - finalize, - &ribs[ns], - ignore_binding, - ) { - // we found a locally-imported or available item/module - Some(LexicalScopeBinding::Item(binding)) => Ok(binding), - // we found a local variable or type param - Some(LexicalScopeBinding::Res(res)) => return FindBindingResult::Res(res), - _ => Err(Determinacy::determined(finalize.is_some())), + let binding = if let Some(module) = module { + self.resolve_ident_in_module( + module, + ident, + ns, + parent_scope, + finalize, + ignore_binding, + ) + } else if let Some(ribs) = ribs && let Some(TypeNS | ValueNS) = opt_ns { + match self.resolve_ident_in_lexical_scope( + ident, + ns, + parent_scope, + finalize, + &ribs[ns], + ignore_binding, + ) { + // we found a locally-imported or available item/module + Some(LexicalScopeBinding::Item(binding)) => Ok(binding), + // we found a local variable or type param + Some(LexicalScopeBinding::Res(res)) => { + record_segment_res(self, res); + return PathResult::NonModule(PartialRes::with_unresolved_segments( + res, + path.len() - 1, + )); } - } else { - let scopes = ScopeSet::All(ns, opt_ns.is_none()); - this.early_resolve_ident_in_lexical_scope( - ident, - scopes, - parent_scope, - finalize, - finalize.is_some(), - ignore_binding, - ) - }; - FindBindingResult::Binding(binding) - }; - let binding = match find_binding_in_ns(self, ns) { - FindBindingResult::Res(res) => { - record_segment_res(self, res); - return PathResult::NonModule(PartialRes::with_unresolved_segments( - res, - path.len() - 1, - )); + _ => Err(Determinacy::determined(finalize.is_some())), } - FindBindingResult::Binding(binding) => binding, + } else { + self.early_resolve_ident_in_lexical_scope( + ident, + ScopeSet::All(ns, opt_ns.is_none()), + parent_scope, + finalize, + finalize.is_some(), + ignore_binding, + ) }; + match binding { Ok(binding) => { if segment_idx == 1 { second_binding = Some(binding); } let res = binding.res(); + + // Mark every privacy error in this path with the res to the last element. This allows us + // to detect the item the user cares about and either find an alternative import, or tell + // the user it is not accessible. + for error in &mut self.privacy_errors[privacy_errors_len..] { + error.outermost_res = Some((res, ident)); + } + let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res); if let Some(next_module) = binding.module() { module = Some(ModuleOrUniformRoot::Module(next_module)); diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 47d8e5993fd..44453309920 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -792,6 +792,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }; let prev_ambiguity_errors_len = self.ambiguity_errors.len(); let finalize = Finalize::with_root_span(import.root_id, import.span, import.root_span); + + // We'll provide more context to the privacy errors later, up to `len`. + let privacy_errors_len = self.privacy_errors.len(); + let path_res = self.resolve_path( &import.module_path, None, @@ -931,6 +935,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { _ => unreachable!(), }; + if self.privacy_errors.len() != privacy_errors_len { + // Get the Res for the last element, so that we can point to alternative ways of + // importing it if available. + let mut path = import.module_path.clone(); + path.push(Segment::from_ident(ident)); + if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = + self.resolve_path(&path, None, &import.parent_scope, Some(finalize), ignore_binding) + { + let res = module.res().map(|r| (r, ident)); + for error in &mut self.privacy_errors[privacy_errors_len..] { + error.outermost_res = res; + } + } + } + let mut all_ns_err = true; self.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index ddd75ea3b33..9f4573ea025 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -6,6 +6,7 @@ //! If you wonder why there's no `early.rs`, that's because it's split into three files - //! `build_reduced_graph.rs`, `macros.rs` and `imports.rs`. +use crate::errors::ImportsCannotReferTo; use crate::BindingKey; use crate::{path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding}; use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult}; @@ -2244,12 +2245,13 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { _ => &[TypeNS], }; let report_error = |this: &Self, ns| { - let what = if ns == TypeNS { "type parameters" } else { "local variables" }; if this.should_report_errs() { + let what = if ns == TypeNS { "type parameters" } else { "local variables" }; this.r .tcx .sess - .span_err(ident.span, format!("imports cannot refer to {}", what)); + .create_err(ImportsCannotReferTo { span: ident.span, what }) + .emit(); } }; diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 7284b33f09d..475772734ff 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1831,6 +1831,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { path, accessible: true, note: None, + via_import: false, }, )); } else { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 82b333fee28..8c1cd2f1557 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -689,10 +689,13 @@ impl<'a> NameBindingKind<'a> { } } +#[derive(Debug)] struct PrivacyError<'a> { ident: Ident, binding: &'a NameBinding<'a>, dedup_span: Span, + outermost_res: Option<(Res, Ident)>, + parent_scope: ParentScope<'a>, } #[derive(Debug)] diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index ca4f3331b9a..4dcef8f6efd 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -1,7 +1,9 @@ //! A bunch of methods and structures more or less related to resolving macros and //! interface provided by `Resolver` to macro expander. -use crate::errors::{self, AddAsNonDerive, MacroExpectedFound, RemoveSurroundingDerive}; +use crate::errors::{ + self, AddAsNonDerive, CannotFindIdentInThisScope, MacroExpectedFound, RemoveSurroundingDerive, +}; use crate::Namespace::*; use crate::{BuiltinMacroState, Determinacy}; use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet}; @@ -793,8 +795,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } Err(..) => { let expected = kind.descr_expected(); - let msg = format!("cannot find {} `{}` in this scope", expected, ident); - let mut err = self.tcx.sess.struct_span_err(ident.span, msg); + + let mut err = self.tcx.sess.create_err(CannotFindIdentInThisScope { + span: ident.span, + expected, + ident, + }); + self.unresolved_macro_suggestions(&mut err, kind, &parent_scope, ident, krate); err.emit(); } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 3d9f0a4e268..270d8331602 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1436,6 +1436,8 @@ options! { "output statistics about monomorphization collection"), dump_mono_stats_format: DumpMonoStatsFormat = (DumpMonoStatsFormat::Markdown, parse_dump_mono_stats, [UNTRACKED], "the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)"), + dump_solver_proof_tree: bool = (false, parse_bool, [UNTRACKED], + "dump a proof tree for every goal evaluated by the new trait solver"), dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED], "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"), dylib_lto: bool = (false, parse_bool, [UNTRACKED], @@ -1611,7 +1613,7 @@ options! { plt: Option<bool> = (None, parse_opt_bool, [TRACKED], "whether to use the PLT when calling into shared libraries; only has effect for PIC code on systems with ELF binaries - (default: PLT is disabled if full relro is enabled)"), + (default: PLT is disabled if full relro is enabled on x86_64)"), polonius: bool = (false, parse_bool, [TRACKED], "enable polonius-based borrow-checker (default: no)"), polymorphize: bool = (false, parse_bool, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 5feea83edb6..ea5beb6f8be 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1009,11 +1009,11 @@ impl Session { self.edition().rust_2024() } - /// Returns `true` if we cannot skip the PLT for shared library calls. + /// Returns `true` if we should use the PLT for shared library calls. pub fn needs_plt(&self) -> bool { - // Check if the current target usually needs PLT to be enabled. + // Check if the current target usually wants PLT to be enabled. // The user can use the command line flag to override it. - let needs_plt = self.target.needs_plt; + let want_plt = self.target.plt_by_default; let dbg_opts = &self.opts.unstable_opts; @@ -1025,8 +1025,8 @@ impl Session { let full_relro = RelroLevel::Full == relro_level; // If user didn't explicitly forced us to use / skip the PLT, - // then try to skip it where possible. - dbg_opts.plt.unwrap_or(needs_plt || !full_relro) + // then use it unless the target doesn't want it by default or the full relro forces it on. + dbg_opts.plt.unwrap_or(want_plt || !full_relro) } /// Checks if LLVM lifetime markers should be emitted. diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 6bd030b13d1..874e34bef60 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -250,15 +250,20 @@ impl Stable for mir::BinOp { use mir::BinOp; match self { BinOp::Add => stable_mir::mir::BinOp::Add, + BinOp::AddUnchecked => stable_mir::mir::BinOp::AddUnchecked, BinOp::Sub => stable_mir::mir::BinOp::Sub, + BinOp::SubUnchecked => stable_mir::mir::BinOp::SubUnchecked, BinOp::Mul => stable_mir::mir::BinOp::Mul, + BinOp::MulUnchecked => stable_mir::mir::BinOp::MulUnchecked, BinOp::Div => stable_mir::mir::BinOp::Div, BinOp::Rem => stable_mir::mir::BinOp::Rem, BinOp::BitXor => stable_mir::mir::BinOp::BitXor, BinOp::BitAnd => stable_mir::mir::BinOp::BitAnd, BinOp::BitOr => stable_mir::mir::BinOp::BitOr, BinOp::Shl => stable_mir::mir::BinOp::Shl, + BinOp::ShlUnchecked => stable_mir::mir::BinOp::ShlUnchecked, BinOp::Shr => stable_mir::mir::BinOp::Shr, + BinOp::ShrUnchecked => stable_mir::mir::BinOp::ShrUnchecked, BinOp::Eq => stable_mir::mir::BinOp::Eq, BinOp::Lt => stable_mir::mir::BinOp::Lt, BinOp::Le => stable_mir::mir::BinOp::Le, @@ -346,7 +351,7 @@ impl<'tcx> Stable for mir::Terminator<'tcx> { target: target.as_usize(), unwind: unwind.stable(), }, - Call { func, args, destination, target, unwind, from_hir_call: _, fn_span: _ } => { + Call { func, args, destination, target, unwind, call_source: _, fn_span: _ } => { Terminator::Call { func: func.stable(), args: args.iter().map(|arg| arg.stable()).collect(), diff --git a/compiler/rustc_smir/src/stable_mir/mir/body.rs b/compiler/rustc_smir/src/stable_mir/mir/body.rs index 9df7b4945b7..468e915d1a0 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/body.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/body.rs @@ -88,15 +88,20 @@ pub enum AssertMessage { #[derive(Clone, Debug)] pub enum BinOp { Add, + AddUnchecked, Sub, + SubUnchecked, Mul, + MulUnchecked, Div, Rem, BitXor, BitAnd, BitOr, Shl, + ShlUnchecked, Shr, + ShrUnchecked, Eq, Lt, Le, diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index e7a53c63e83..3bb9c4920c4 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -65,11 +65,11 @@ use rustc_data_structures::sync::{Lock, Lrc}; use std::borrow::Cow; use std::cmp::{self, Ordering}; -use std::fmt; use std::hash::Hash; use std::ops::{Add, Range, Sub}; use std::path::{Path, PathBuf}; use std::str::FromStr; +use std::{fmt, iter}; use md5::Digest; use md5::Md5; @@ -733,12 +733,15 @@ impl Span { /// else returns the `ExpnData` for the macro definition /// corresponding to the source callsite. pub fn source_callee(self) -> Option<ExpnData> { - fn source_callee(expn_data: ExpnData) -> ExpnData { - let next_expn_data = expn_data.call_site.ctxt().outer_expn_data(); - if !next_expn_data.is_root() { source_callee(next_expn_data) } else { expn_data } - } let expn_data = self.ctxt().outer_expn_data(); - if !expn_data.is_root() { Some(source_callee(expn_data)) } else { None } + + // Create an iterator of call site expansions + iter::successors(Some(expn_data), |expn_data| { + Some(expn_data.call_site.ctxt().outer_expn_data()) + }) + // Find the last expansion which is not root + .take_while(|expn_data| !expn_data.is_root()) + .last() } /// Checks if a span is "internal" to a macro in which `#[unstable]` @@ -777,7 +780,7 @@ impl Span { pub fn macro_backtrace(mut self) -> impl Iterator<Item = ExpnData> { let mut prev_span = DUMMY_SP; - std::iter::from_fn(move || { + iter::from_fn(move || { loop { let expn_data = self.ctxt().outer_expn_data(); if expn_data.is_root() { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index bd39cbf17ce..c71ed2097b8 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -686,6 +686,7 @@ symbols! { expf32, expf64, explicit_generic_args_with_impl_trait, + explicit_tail_calls, export_name, expr, extended_key_value_attributes, @@ -816,6 +817,7 @@ symbols! { impl_trait_in_bindings, impl_trait_in_fn_trait_return, impl_trait_projections, + implement_via_object, implied_by, import, import_name_type, @@ -869,6 +871,7 @@ symbols! { large_assignments, lateout, lazy_normalization_consts, + lazy_type_alias, le, len, let_chains, diff --git a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs index bb7c39ff26b..f7cdfa71c4b 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs @@ -1,10 +1,10 @@ -use super::apple_base::{opts, Arch}; +use super::apple_base::{opts, tvos_llvm_target, Arch}; use crate::spec::{FramePointer, Target, TargetOptions}; pub fn target() -> Target { let arch = Arch::Arm64; Target { - llvm_target: "arm64-apple-tvos".into(), + llvm_target: tvos_llvm_target(arch).into(), pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(), arch: arch.target_arch(), diff --git a/compiler/rustc_target/src/spec/apple/tests.rs b/compiler/rustc_target/src/spec/apple/tests.rs index 3c90a5e7e93..3b23ddadcc4 100644 --- a/compiler/rustc_target/src/spec/apple/tests.rs +++ b/compiler/rustc_target/src/spec/apple/tests.rs @@ -30,6 +30,9 @@ fn macos_link_environment_unmodified() { for target in all_macos_targets { // macOS targets should only remove information for cross-compiling, but never // for the host. - assert_eq!(target.link_env_remove, crate::spec::cvs!["IPHONEOS_DEPLOYMENT_TARGET"]); + assert_eq!( + target.link_env_remove, + crate::spec::cvs!["IPHONEOS_DEPLOYMENT_TARGET", "TVOS_DEPLOYMENT_TARGET"], + ); } } diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs index ff224631828..8a8d1ab95e8 100644 --- a/compiler/rustc_target/src/spec/apple_base.rs +++ b/compiler/rustc_target/src/spec/apple_base.rs @@ -240,7 +240,12 @@ fn link_env_remove(arch: Arch, os: &'static str) -> StaticCow<[StaticCow<str>]> // Remove the `SDKROOT` environment variable if it's clearly set for the wrong platform, which // may occur when we're linking a custom build script while targeting iOS for example. if let Ok(sdkroot) = env::var("SDKROOT") { - if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("iPhoneSimulator.platform") + if sdkroot.contains("iPhoneOS.platform") + || sdkroot.contains("iPhoneSimulator.platform") + || sdkroot.contains("AppleTVOS.platform") + || sdkroot.contains("AppleTVSimulator.platform") + || sdkroot.contains("WatchOS.platform") + || sdkroot.contains("WatchSimulator.platform") { env_remove.push("SDKROOT".into()) } @@ -249,6 +254,7 @@ fn link_env_remove(arch: Arch, os: &'static str) -> StaticCow<[StaticCow<str>]> // "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld", // although this is apparently ignored when using the linker at "/usr/bin/ld". env_remove.push("IPHONEOS_DEPLOYMENT_TARGET".into()); + env_remove.push("TVOS_DEPLOYMENT_TARGET".into()); env_remove.into() } else { // Otherwise if cross-compiling for a different OS/SDK, remove any part @@ -299,6 +305,16 @@ fn tvos_lld_platform_version() -> String { format!("{major}.{minor}") } +pub fn tvos_llvm_target(arch: Arch) -> String { + let (major, minor) = tvos_deployment_target(); + format!("{}-apple-tvos{}.{}.0", arch.target_name(), major, minor) +} + +pub fn tvos_sim_llvm_target(arch: Arch) -> String { + let (major, minor) = tvos_deployment_target(); + format!("{}-apple-tvos{}.{}.0-simulator", arch.target_name(), major, minor) +} + fn watchos_deployment_target() -> (u32, u32) { // If you are looking for the default deployment target, prefer `rustc --print deployment-target`. from_set_deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0)) diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 0f26b703536..c15a330ee74 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1670,7 +1670,7 @@ pub struct TargetOptions { pub static_position_independent_executables: bool, /// Determines if the target always requires using the PLT for indirect /// library calls or not. This controls the default value of the `-Z plt` flag. - pub needs_plt: bool, + pub plt_by_default: bool, /// Either partial, full, or off. Full RELRO makes the dynamic linker /// resolve all symbols at startup and marks the GOT read-only before /// starting the program, preventing overwriting the GOT. @@ -1992,7 +1992,7 @@ impl Default for TargetOptions { no_default_libraries: true, position_independent_executables: false, static_position_independent_executables: false, - needs_plt: false, + plt_by_default: true, relro_level: RelroLevel::None, pre_link_objects: Default::default(), post_link_objects: Default::default(), @@ -2665,7 +2665,7 @@ impl Target { key!(no_default_libraries, bool); key!(position_independent_executables, bool); key!(static_position_independent_executables, bool); - key!(needs_plt, bool); + key!(plt_by_default, bool); key!(relro_level, RelroLevel)?; key!(archive_format); key!(allow_asm, bool); @@ -2921,7 +2921,7 @@ impl ToJson for Target { target_option_val!(no_default_libraries); target_option_val!(position_independent_executables); target_option_val!(static_position_independent_executables); - target_option_val!(needs_plt); + target_option_val!(plt_by_default); target_option_val!(relro_level); target_option_val!(archive_format); target_option_val!(allow_asm); diff --git a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs index 76de7d20c4c..2ec4d9569e3 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs @@ -1,12 +1,13 @@ -use super::apple_base::{opts, Arch}; +use super::apple_base::{opts, tvos_sim_llvm_target, Arch}; use crate::spec::{StackProbeType, Target, TargetOptions}; pub fn target() -> Target { let arch = Arch::X86_64_sim; Target { - llvm_target: "x86_64-apple-tvos".into(), + llvm_target: tvos_sim_llvm_target(arch).into(), pointer_width: 64, - data_layout: "e-m:o-i64:64-f80:128-n8:16:32:64-S128".into(), + data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + .into(), arch: arch.target_arch(), options: TargetOptions { max_atomic_width: Some(128), diff --git a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs index cba6fda19dc..a7ed74f4721 100644 --- a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs +++ b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs @@ -63,6 +63,7 @@ pub fn target() -> Target { linker: Some("rust-lld".into()), max_atomic_width: Some(64), cpu: "x86-64".into(), + plt_by_default: false, features: "+rdrnd,+rdseed,+lvi-cfi,+lvi-load-hardening".into(), llvm_args: cvs!["--x86-experimental-lvi-inline-asm-hardening"], position_independent_executables: true, diff --git a/compiler/rustc_target/src/spec/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/x86_64_linux_android.rs index a3bdb5f5465..c110674fd87 100644 --- a/compiler/rustc_target/src/spec/x86_64_linux_android.rs +++ b/compiler/rustc_target/src/spec/x86_64_linux_android.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, T pub fn target() -> Target { let mut base = super::android_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; // https://developer.android.com/ndk/guides/abis.html#86-64 base.features = "+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt".into(); base.max_atomic_width = Some(64); diff --git a/compiler/rustc_target/src/spec/x86_64_pc_nto_qnx710.rs b/compiler/rustc_target/src/spec/x86_64_pc_nto_qnx710.rs index 6fb2dfd807a..8424757df07 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_nto_qnx710.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_nto_qnx710.rs @@ -10,6 +10,7 @@ pub fn target() -> Target { arch: "x86_64".into(), options: TargetOptions { cpu: "x86-64".into(), + plt_by_default: false, max_atomic_width: Some(64), pre_link_args: TargetOptions::link_args( LinkerFlavor::Gnu(Cc::Yes, Lld::No), diff --git a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs index d2906d6c4ae..e2c59d2938e 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs @@ -4,6 +4,7 @@ pub fn target() -> Target { let mut base = super::solaris_base::opts(); base.add_pre_link_args(LinkerFlavor::Unix(Cc::Yes), &["-m64"]); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.vendor = "pc".into(); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs index 37feaa9dbbf..1b8885c34da 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, Target}; pub fn target() -> Target { let mut base = super::windows_gnu_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; // Use high-entropy 64 bit address space for ASLR base.add_pre_link_args( LinkerFlavor::Gnu(Cc::No, Lld::No), diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs index 039bc2bd2bb..8f5e398a0be 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, Target}; pub fn target() -> Target { let mut base = super::windows_gnullvm_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.linker = Some("x86_64-w64-mingw32-clang".into()); diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs index 081806aa698..6b897ca7070 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs @@ -3,6 +3,7 @@ use crate::spec::Target; pub fn target() -> Target { let mut base = super::windows_msvc_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs index 0f31ea86b3f..650065f6330 100644 --- a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs +++ b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs @@ -4,6 +4,7 @@ pub fn target() -> Target { let mut base = super::solaris_base::opts(); base.add_pre_link_args(LinkerFlavor::Unix(Cc::Yes), &["-m64"]); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.vendor = "sun".into(); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs index 67ce3768db0..3b8e75977b5 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::dragonfly_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs index b41e5842aad..b2d91d09996 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::freebsd_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/x86_64_unknown_fuchsia.rs index a3231d19f4c..bee93541960 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_fuchsia.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_fuchsia.rs @@ -3,6 +3,7 @@ use crate::spec::{SanitizerSet, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::fuchsia_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::X86; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs index 9a7a3b501cf..16ed3150e6e 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::haiku_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs index fb1af33f80a..74ef2527c36 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs @@ -3,6 +3,7 @@ use crate::spec::{StackProbeType, Target}; pub fn target() -> Target { let mut base = super::hermit_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.features = "+rdrnd,+rdseed".into(); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs index ca5b62e279c..9259cfe5f0e 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs @@ -4,6 +4,7 @@ pub fn target() -> Target { let mut base = super::illumos_base::opts(); base.add_pre_link_args(LinkerFlavor::Unix(Cc::Yes), &["-m64", "-std=c99"]); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs index 26da7e80011..912d289c47f 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs @@ -3,6 +3,7 @@ use crate::spec::{PanicStrategy, Target}; pub fn target() -> Target { let mut base = super::l4re_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.panic_strategy = PanicStrategy::Abort; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs index deb15c02c68..2f970f87cc6 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs index 626d5b480c6..5469d02c592 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { base.has_thread_local = false; // BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI // breaks code gen. See LLVM bug 36743 - base.needs_plt = true; + base.plt_by_default = true; Target { llvm_target: "x86_64-unknown-linux-gnux32".into(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs index bf4cf7d7bec..7154f5fa306 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs index 74c434935ba..2e7bf34f7d2 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, T pub fn target() -> Target { let mut base = super::netbsd_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_none.rs b/compiler/rustc_target/src/spec/x86_64_unknown_none.rs index 43c5ce78ce3..fe3b24f2d4a 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_none.rs @@ -10,6 +10,7 @@ use super::{RelroLevel, SanitizerSet, StackProbeType, Target, TargetOptions}; pub fn target() -> Target { let opts = TargetOptions { cpu: "x86-64".into(), + plt_by_default: false, max_atomic_width: Some(64), stack_probes: StackProbeType::X86, position_independent_executables: true, diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs index 8e4d42a0aca..86fa9bf7ed2 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::openbsd_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs index b47f15cf578..decc9736782 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::redox_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs b/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs index a7ae17839da..67664a74710 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs @@ -10,6 +10,7 @@ use crate::spec::Target; pub fn target() -> Target { let mut base = super::uefi_msvc_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); // We disable MMX and SSE for now, even though UEFI allows using them. Problem is, you have to diff --git a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs index c3eaa6939bb..1a9d2a57182 100644 --- a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, Target}; pub fn target() -> Target { let mut base = super::windows_uwp_gnu_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; // Use high-entropy 64 bit address space for ASLR base.add_pre_link_args( LinkerFlavor::Gnu(Cc::No, Lld::No), diff --git a/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs index b2769350bf6..1ae403fa83f 100644 --- a/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs @@ -3,6 +3,7 @@ use crate::spec::Target; pub fn target() -> Target { let mut base = super::windows_uwp_msvc_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs index 365ade6bcf9..a7c4aaecf91 100644 --- a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::vxworks_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs index 66a4d36a1e5..ca7fcfd8ca1 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs @@ -1,5 +1,6 @@ use super::{EvalCtxt, SolverMode}; use rustc_infer::traits::query::NoSolution; +use rustc_middle::traits::solve::inspect::CandidateKind; use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; use rustc_middle::ty; @@ -109,10 +110,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { direction: ty::AliasRelationDirection, invert: Invert, ) -> QueryResult<'tcx> { - self.probe(|ecx| { - ecx.normalizes_to_inner(param_env, alias, other, direction, invert)?; - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) + self.probe(|r| CandidateKind::Candidate { name: "normalizes-to".into(), result: *r }).enter( + |ecx| { + ecx.normalizes_to_inner(param_env, alias, other, direction, invert)?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }, + ) } fn normalizes_to_inner( @@ -153,18 +156,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { alias_rhs: ty::AliasTy<'tcx>, direction: ty::AliasRelationDirection, ) -> QueryResult<'tcx> { - self.probe(|ecx| { - match direction { - ty::AliasRelationDirection::Equate => { - ecx.eq(param_env, alias_lhs, alias_rhs)?; - } - ty::AliasRelationDirection::Subtype => { - ecx.sub(param_env, alias_lhs, alias_rhs)?; + self.probe(|r| CandidateKind::Candidate { name: "substs relate".into(), result: *r }).enter( + |ecx| { + match direction { + ty::AliasRelationDirection::Equate => { + ecx.eq(param_env, alias_lhs, alias_rhs)?; + } + ty::AliasRelationDirection::Subtype => { + ecx.sub(param_env, alias_lhs, alias_rhs)?; + } } - } - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }, + ) } fn assemble_bidirectional_normalizes_to_candidate( @@ -174,22 +179,23 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { rhs: ty::Term<'tcx>, direction: ty::AliasRelationDirection, ) -> QueryResult<'tcx> { - self.probe(|ecx| { - ecx.normalizes_to_inner( - param_env, - lhs.to_alias_ty(ecx.tcx()).unwrap(), - rhs, - direction, - Invert::No, - )?; - ecx.normalizes_to_inner( - param_env, - rhs.to_alias_ty(ecx.tcx()).unwrap(), - lhs, - direction, - Invert::Yes, - )?; - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) + self.probe(|r| CandidateKind::Candidate { name: "bidir normalizes-to".into(), result: *r }) + .enter(|ecx| { + ecx.normalizes_to_inner( + param_env, + lhs.to_alias_ty(ecx.tcx()).unwrap(), + rhs, + direction, + Invert::No, + )?; + ecx.normalizes_to_inner( + param_env, + rhs.to_alias_ty(ecx.tcx()).unwrap(), + lhs, + direction, + Invert::Yes, + )?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 543611daae8..cde8a52cdec 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -8,6 +8,7 @@ use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::util::elaborate; use rustc_infer::traits::Reveal; +use rustc_middle::traits::solve::inspect::CandidateKind; use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult}; use rustc_middle::ty::fast_reject::TreatProjections; use rustc_middle::ty::TypeFoldable; @@ -105,7 +106,7 @@ pub(super) trait GoalKind<'tcx>: fn probe_and_match_goal_against_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - assumption: ty::Binder<'tcx, ty::Clause<'tcx>>, + assumption: ty::Clause<'tcx>, then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>, ) -> QueryResult<'tcx>; @@ -115,7 +116,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_implied_clause( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - assumption: ty::Binder<'tcx, ty::Clause<'tcx>>, + assumption: ty::Clause<'tcx>, requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>, ) -> QueryResult<'tcx> { Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| { @@ -131,7 +132,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_alias_bound_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - assumption: ty::Binder<'tcx, ty::Clause<'tcx>>, + assumption: ty::Clause<'tcx>, ) -> QueryResult<'tcx> { Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| { ecx.validate_alias_bound_self_from_param_env(goal) @@ -144,7 +145,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_object_bound_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - assumption: ty::Binder<'tcx, ty::Clause<'tcx>>, + assumption: ty::Clause<'tcx>, ) -> QueryResult<'tcx> { Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| { let tcx = ecx.tcx(); @@ -336,37 +337,38 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { return }; - let normalized_self_candidates: Result<_, NoSolution> = self.probe(|ecx| { - ecx.with_incremented_depth( - |ecx| { - let result = ecx.evaluate_added_goals_and_make_canonical_response( - Certainty::Maybe(MaybeCause::Overflow), - )?; - Ok(vec![Candidate { source: CandidateSource::BuiltinImpl, result }]) - }, - |ecx| { - let normalized_ty = ecx.next_ty_infer(); - let normalizes_to_goal = goal.with( - tcx, - ty::Binder::dummy(ty::ProjectionPredicate { - projection_ty, - term: normalized_ty.into(), - }), - ); - ecx.add_goal(normalizes_to_goal); - let _ = ecx.try_evaluate_added_goals().inspect_err(|_| { - debug!("self type normalization failed"); - })?; - let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty); - debug!(?normalized_ty, "self type normalized"); - // NOTE: Alternatively we could call `evaluate_goal` here and only - // have a `Normalized` candidate. This doesn't work as long as we - // use `CandidateSource` in winnowing. - let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); - Ok(ecx.assemble_and_evaluate_candidates(goal)) - }, - ) - }); + let normalized_self_candidates: Result<_, NoSolution> = + self.probe(|_| CandidateKind::NormalizedSelfTyAssembly).enter(|ecx| { + ecx.with_incremented_depth( + |ecx| { + let result = ecx.evaluate_added_goals_and_make_canonical_response( + Certainty::Maybe(MaybeCause::Overflow), + )?; + Ok(vec![Candidate { source: CandidateSource::BuiltinImpl, result }]) + }, + |ecx| { + let normalized_ty = ecx.next_ty_infer(); + let normalizes_to_goal = goal.with( + tcx, + ty::Binder::dummy(ty::ProjectionPredicate { + projection_ty, + term: normalized_ty.into(), + }), + ); + ecx.add_goal(normalizes_to_goal); + let _ = ecx.try_evaluate_added_goals().inspect_err(|_| { + debug!("self type normalization failed"); + })?; + let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty); + debug!(?normalized_ty, "self type normalized"); + // NOTE: Alternatively we could call `evaluate_goal` here and only + // have a `Normalized` candidate. This doesn't work as long as we + // use `CandidateSource` in winnowing. + let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); + Ok(ecx.assemble_and_evaluate_candidates(goal)) + }, + ) + }); if let Ok(normalized_self_candidates) = normalized_self_candidates { candidates.extend(normalized_self_candidates); @@ -520,13 +522,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { for assumption in self.tcx().item_bounds(alias_ty.def_id).subst(self.tcx(), alias_ty.substs) { - if let Some(clause) = assumption.as_clause() { - match G::consider_alias_bound_candidate(self, goal, clause) { - Ok(result) => { - candidates.push(Candidate { source: CandidateSource::AliasBound, result }) - } - Err(NoSolution) => (), + match G::consider_alias_bound_candidate(self, goal, assumption) { + Ok(result) => { + candidates.push(Candidate { source: CandidateSource::AliasBound, result }) } + Err(NoSolution) => (), } } } @@ -636,6 +636,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, G>, candidates: &mut Vec<Candidate<'tcx>>, ) { + let tcx = self.tcx(); + if !tcx.trait_def(goal.predicate.trait_def_id(tcx)).implement_via_object { + return; + } + let self_ty = goal.predicate.self_ty(); let bounds = match *self_ty.kind() { ty::Bool @@ -668,7 +673,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ty::Dynamic(bounds, ..) => bounds, }; - let tcx = self.tcx(); let own_bounds: FxIndexSet<_> = bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty)).collect(); for assumption in elaborate(tcx, own_bounds.iter().copied()) diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 97b86a06c8c..439cf788ab4 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -353,7 +353,11 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( // FIXME(associated_const_equality): Also add associated consts to // the requirements here. if item.kind == ty::AssocKind::Type { - requirements.extend(tcx.item_bounds(item.def_id).subst(tcx, trait_ref.substs)); + requirements.extend( + tcx.item_bounds(item.def_id) + .subst_iter(tcx, trait_ref.substs) + .map(|clause| clause.as_predicate()), + ); } } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 8625958ff5a..b42bbf91e90 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -9,9 +9,10 @@ use rustc_infer::infer::{ use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::ObligationCause; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; +use rustc_middle::traits::solve::inspect::{self, CandidateKind}; use rustc_middle::traits::solve::{ - CanonicalInput, CanonicalResponse, Certainty, MaybeCause, PredefinedOpaques, - PredefinedOpaquesData, QueryResult, + CanonicalInput, CanonicalResponse, Certainty, IsNormalizesToHack, MaybeCause, + PredefinedOpaques, PredefinedOpaquesData, QueryResult, }; use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::{ @@ -23,11 +24,13 @@ use std::ops::ControlFlow; use crate::traits::specialization_graph; +use super::inspect::ProofTreeBuilder; use super::search_graph::{self, OverflowHandler}; use super::SolverMode; use super::{search_graph::SearchGraph, Goal}; mod canonical; +mod probe; pub struct EvalCtxt<'a, 'tcx> { /// The inference context that backs (mostly) inference and placeholder terms @@ -73,12 +76,8 @@ pub struct EvalCtxt<'a, 'tcx> { // ambiguous goals. Instead, a probe needs to be introduced somewhere in the // evaluation code. tainted: Result<(), NoSolution>, -} -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub(super) enum IsNormalizesToHack { - Yes, - No, + inspect: ProofTreeBuilder<'tcx>, } #[derive(Debug, Clone)] @@ -110,6 +109,12 @@ impl NestedGoals<'_> { } } +#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)] +pub enum GenerateProofTree { + Yes, + No, +} + pub trait InferCtxtEvalExt<'tcx> { /// Evaluates a goal from **outside** of the trait solver. /// @@ -118,7 +123,11 @@ pub trait InferCtxtEvalExt<'tcx> { fn evaluate_root_goal( &self, goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>; + generate_proof_tree: GenerateProofTree, + ) -> ( + Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>, + Option<inspect::GoalEvaluation<'tcx>>, + ); } impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { @@ -126,7 +135,11 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { fn evaluate_root_goal( &self, goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> { + generate_proof_tree: GenerateProofTree, + ) -> ( + Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>, + Option<inspect::GoalEvaluation<'tcx>>, + ) { let mode = if self.intercrate { SolverMode::Coherence } else { SolverMode::Normal }; let mut search_graph = search_graph::SearchGraph::new(self.tcx, mode); @@ -143,16 +156,26 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { var_values: CanonicalVarValues::dummy(), nested_goals: NestedGoals::new(), tainted: Ok(()), + inspect: (self.tcx.sess.opts.unstable_opts.dump_solver_proof_tree + || matches!(generate_proof_tree, GenerateProofTree::Yes)) + .then(ProofTreeBuilder::new_root) + .unwrap_or_else(ProofTreeBuilder::new_noop), }; let result = ecx.evaluate_goal(IsNormalizesToHack::No, goal); + let tree = ecx.inspect.finalize(); + if let Some(tree) = &tree { + // module to allow more granular RUSTC_LOG filtering to just proof tree output + super::inspect::dump::print_tree(tree); + } + assert!( ecx.nested_goals.is_empty(), "root `EvalCtxt` should not have any goals added to it" ); assert!(search_graph.is_empty()); - result + (result, tree) } } @@ -170,58 +193,72 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { /// Instead of calling this function directly, use either [EvalCtxt::evaluate_goal] /// if you're inside of the solver or [InferCtxtEvalExt::evaluate_root_goal] if you're /// outside of it. - #[instrument(level = "debug", skip(tcx, search_graph), ret)] + #[instrument(level = "debug", skip(tcx, search_graph, goal_evaluation), ret)] fn evaluate_canonical_goal( tcx: TyCtxt<'tcx>, search_graph: &'a mut search_graph::SearchGraph<'tcx>, canonical_input: CanonicalInput<'tcx>, + mut goal_evaluation: &mut ProofTreeBuilder<'tcx>, ) -> QueryResult<'tcx> { + goal_evaluation.canonicalized_goal(canonical_input); + // Deal with overflow, caching, and coinduction. // // The actual solver logic happens in `ecx.compute_goal`. - search_graph.with_new_goal(tcx, canonical_input, |search_graph| { - let intercrate = match search_graph.solver_mode() { - SolverMode::Normal => false, - SolverMode::Coherence => true, - }; - let (ref infcx, input, var_values) = tcx - .infer_ctxt() - .intercrate(intercrate) - .with_next_trait_solver(true) - .with_opaque_type_inference(canonical_input.value.anchor) - .build_with_canonical(DUMMY_SP, &canonical_input); - - let mut ecx = EvalCtxt { - infcx, - var_values, - predefined_opaques_in_body: input.predefined_opaques_in_body, - max_input_universe: canonical_input.max_universe, - search_graph, - nested_goals: NestedGoals::new(), - tainted: Ok(()), - }; - - for &(key, ty) in &input.predefined_opaques_in_body.opaque_types { - ecx.insert_hidden_type(key, input.goal.param_env, ty) - .expect("failed to prepopulate opaque types"); - } + search_graph.with_new_goal( + tcx, + canonical_input, + goal_evaluation, + |search_graph, goal_evaluation| { + let intercrate = match search_graph.solver_mode() { + SolverMode::Normal => false, + SolverMode::Coherence => true, + }; + let (ref infcx, input, var_values) = tcx + .infer_ctxt() + .intercrate(intercrate) + .with_next_trait_solver(true) + .with_opaque_type_inference(canonical_input.value.anchor) + .build_with_canonical(DUMMY_SP, &canonical_input); + + let mut ecx = EvalCtxt { + infcx, + var_values, + predefined_opaques_in_body: input.predefined_opaques_in_body, + max_input_universe: canonical_input.max_universe, + search_graph, + nested_goals: NestedGoals::new(), + tainted: Ok(()), + inspect: goal_evaluation.new_goal_evaluation_step(input), + }; + + for &(key, ty) in &input.predefined_opaques_in_body.opaque_types { + ecx.insert_hidden_type(key, input.goal.param_env, ty) + .expect("failed to prepopulate opaque types"); + } - if !ecx.nested_goals.is_empty() { - panic!("prepopulating opaque types shouldn't add goals: {:?}", ecx.nested_goals); - } + if !ecx.nested_goals.is_empty() { + panic!( + "prepopulating opaque types shouldn't add goals: {:?}", + ecx.nested_goals + ); + } - let result = ecx.compute_goal(input.goal); + let result = ecx.compute_goal(input.goal); + ecx.inspect.query_result(result); + goal_evaluation.goal_evaluation_step(ecx.inspect); - // When creating a query response we clone the opaque type constraints - // instead of taking them. This would cause an ICE here, since we have - // assertions against dropping an `InferCtxt` without taking opaques. - // FIXME: Once we remove support for the old impl we can remove this. - if input.anchor != DefiningAnchor::Error { - let _ = infcx.take_opaque_types(); - } + // When creating a query response we clone the opaque type constraints + // instead of taking them. This would cause an ICE here, since we have + // assertions against dropping an `InferCtxt` without taking opaques. + // FIXME: Once we remove support for the old impl we can remove this. + if input.anchor != DefiningAnchor::Error { + let _ = infcx.take_opaque_types(); + } - result - }) + result + }, + ) } /// Recursively evaluates `goal`, returning whether any inference vars have @@ -232,16 +269,37 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { goal: Goal<'tcx, ty::Predicate<'tcx>>, ) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> { let (orig_values, canonical_goal) = self.canonicalize_goal(goal); - let canonical_response = - EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; + let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, is_normalizes_to_hack); + let canonical_response = EvalCtxt::evaluate_canonical_goal( + self.tcx(), + self.search_graph, + canonical_goal, + &mut goal_evaluation, + ); + goal_evaluation.query_result(canonical_response); + let canonical_response = match canonical_response { + Err(e) => { + self.inspect.goal_evaluation(goal_evaluation); + return Err(e); + } + Ok(response) => response, + }; let has_changed = !canonical_response.value.var_values.is_identity() || !canonical_response.value.external_constraints.opaque_types.is_empty(); - let (certainty, nested_goals) = self.instantiate_and_apply_query_response( + let (certainty, nested_goals) = match self.instantiate_and_apply_query_response( goal.param_env, orig_values, canonical_response, - )?; + ) { + Err(e) => { + self.inspect.goal_evaluation(goal_evaluation); + return Err(e); + } + Ok(response) => response, + }; + goal_evaluation.returned_goals(&nested_goals); + self.inspect.goal_evaluation(goal_evaluation); if !has_changed && !nested_goals.is_empty() { bug!("an unchanged goal shouldn't have any side-effects on instantiation"); @@ -261,8 +319,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { { debug!("rerunning goal to check result is stable"); let (_orig_values, canonical_goal) = self.canonicalize_goal(goal); - let new_canonical_response = - EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; + let new_canonical_response = EvalCtxt::evaluate_canonical_goal( + self.tcx(), + self.search_graph, + canonical_goal, + // FIXME(-Ztrait-solver=next): we do not track what happens in `evaluate_canonical_goal` + &mut ProofTreeBuilder::new_noop(), + )?; // We only check for modulo regions as we convert all regions in // the input to new existentials, even if they're expected to be // `'static` or a placeholder region. @@ -290,19 +353,19 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let kind = predicate.kind(); if let Some(kind) = kind.no_bound_vars() { match kind { - ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { self.compute_trait_goal(Goal { param_env, predicate }) } - ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => { self.compute_projection_goal(Goal { param_env, predicate }) } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => { self.compute_type_outlives_goal(Goal { param_env, predicate }) } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => { self.compute_region_outlives_goal(Goal { param_env, predicate }) } - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) }) } ty::PredicateKind::Subtype(predicate) => { @@ -319,14 +382,14 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { ty::PredicateKind::ObjectSafe(trait_def_id) => { self.compute_object_safe_goal(trait_def_id) } - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { self.compute_well_formed_goal(Goal { param_env, predicate: arg }) } ty::PredicateKind::Ambiguous => { self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } // FIXME: implement this predicate :) - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(_)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(_)) => { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } ty::PredicateKind::ConstEquate(_, _) => { @@ -353,12 +416,17 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // the certainty of all the goals. #[instrument(level = "debug", skip(self))] pub(super) fn try_evaluate_added_goals(&mut self) -> Result<Certainty, NoSolution> { + let inspect = self.inspect.new_evaluate_added_goals(); + let inspect = core::mem::replace(&mut self.inspect, inspect); + let mut goals = core::mem::replace(&mut self.nested_goals, NestedGoals::new()); let mut new_goals = NestedGoals::new(); let response = self.repeat_while_none( |_| Ok(Certainty::Maybe(MaybeCause::Overflow)), |this| { + this.inspect.evaluate_added_goals_loop_start(); + let mut has_changed = Err(Certainty::Yes); if let Some(goal) = goals.normalizes_to_hack_goal.take() { @@ -447,29 +515,21 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { }, ); + self.inspect.eval_added_goals_result(response); + if response.is_err() { self.tainted = Err(NoSolution); } + let goal_evaluations = std::mem::replace(&mut self.inspect, inspect); + self.inspect.added_goals_evaluation(goal_evaluations); + self.nested_goals = goals; response } } impl<'tcx> EvalCtxt<'_, 'tcx> { - pub(super) fn probe<T>(&mut self, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T) -> T { - let mut ecx = EvalCtxt { - infcx: self.infcx, - var_values: self.var_values, - predefined_opaques_in_body: self.predefined_opaques_in_body, - max_input_universe: self.max_input_universe, - search_graph: self.search_graph, - nested_goals: self.nested_goals.clone(), - tainted: self.tainted, - }; - self.infcx.probe(|_| f(&mut ecx)) - } - pub(super) fn tcx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -750,13 +810,15 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { pub(super) fn add_item_bounds_for_hidden_type( &mut self, - opaque_type_key: OpaqueTypeKey<'tcx>, + opaque_def_id: DefId, + opaque_substs: ty::SubstsRef<'tcx>, param_env: ty::ParamEnv<'tcx>, hidden_ty: Ty<'tcx>, ) { let mut obligations = Vec::new(); self.infcx.add_item_bounds_for_hidden_type( - opaque_type_key, + opaque_def_id, + opaque_substs, ObligationCause::dummy(), param_env, hidden_ty, @@ -781,14 +843,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { if candidate_key.def_id != key.def_id { continue; } - values.extend(self.probe(|ecx| { - for (a, b) in std::iter::zip(candidate_key.substs, key.substs) { - ecx.eq(param_env, a, b)?; - } - ecx.eq(param_env, candidate_ty, ty)?; - ecx.add_item_bounds_for_hidden_type(candidate_key, param_env, candidate_ty); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - })); + values.extend( + self.probe(|r| CandidateKind::Candidate { + name: "opaque type storage".into(), + result: *r, + }) + .enter(|ecx| { + for (a, b) in std::iter::zip(candidate_key.substs, key.substs) { + ecx.eq(param_env, a, b)?; + } + ecx.eq(param_env, candidate_ty, ty)?; + ecx.add_item_bounds_for_hidden_type( + candidate_key.def_id.to_def_id(), + candidate_key.substs, + param_env, + candidate_ty, + ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }), + ); } values } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs new file mode 100644 index 00000000000..5d912fc039d --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs @@ -0,0 +1,47 @@ +use super::EvalCtxt; +use rustc_middle::traits::solve::inspect; +use std::marker::PhantomData; + +pub(in crate::solve) struct ProbeCtxt<'me, 'a, 'tcx, F, T> { + ecx: &'me mut EvalCtxt<'a, 'tcx>, + probe_kind: F, + _result: PhantomData<T>, +} + +impl<'tcx, F, T> ProbeCtxt<'_, '_, 'tcx, F, T> +where + F: FnOnce(&T) -> inspect::CandidateKind<'tcx>, +{ + pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T) -> T { + let ProbeCtxt { ecx: outer_ecx, probe_kind, _result } = self; + + let mut nested_ecx = EvalCtxt { + infcx: outer_ecx.infcx, + var_values: outer_ecx.var_values, + predefined_opaques_in_body: outer_ecx.predefined_opaques_in_body, + max_input_universe: outer_ecx.max_input_universe, + search_graph: outer_ecx.search_graph, + nested_goals: outer_ecx.nested_goals.clone(), + tainted: outer_ecx.tainted, + inspect: outer_ecx.inspect.new_goal_candidate(), + }; + let r = nested_ecx.infcx.probe(|_| f(&mut nested_ecx)); + if !outer_ecx.inspect.is_noop() { + let cand_kind = probe_kind(&r); + nested_ecx.inspect.candidate_kind(cand_kind); + outer_ecx.inspect.goal_candidate(nested_ecx.inspect); + } + r + } +} + +impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { + /// `probe_kind` is only called when proof tree building is enabled so it can be + /// as expensive as necessary to output the desired information. + pub(in crate::solve) fn probe<F, T>(&mut self, probe_kind: F) -> ProbeCtxt<'_, 'a, 'tcx, F, T> + where + F: FnOnce(&T) -> inspect::CandidateKind<'tcx>, + { + ProbeCtxt { ecx: self, probe_kind, _result: PhantomData } + } +} diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 65c8d9c8f69..f8f1239d5b4 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -10,6 +10,7 @@ use rustc_infer::traits::{ use rustc_middle::ty; use rustc_middle::ty::error::{ExpectedFound, TypeError}; +use super::eval_ctxt::GenerateProofTree; use super::{Certainty, InferCtxtEvalExt}; /// A trait engine using the new trait solver. @@ -46,8 +47,11 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { self.obligations .drain(..) .map(|obligation| { - let code = - infcx.probe(|_| match infcx.evaluate_root_goal(obligation.clone().into()) { + let code = infcx.probe(|_| { + match infcx + .evaluate_root_goal(obligation.clone().into(), GenerateProofTree::No) + .0 + { Ok((_, Certainty::Maybe(MaybeCause::Ambiguity), _)) => { FulfillmentErrorCode::CodeAmbiguity { overflow: false } } @@ -60,7 +64,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { Err(_) => { bug!("did not expect selection error when collecting ambiguity errors") } - }); + } + }); FulfillmentError { obligation: obligation.clone(), @@ -81,61 +86,62 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { let mut has_changed = false; for obligation in mem::take(&mut self.obligations) { let goal = obligation.clone().into(); - let (changed, certainty, nested_goals) = match infcx.evaluate_root_goal(goal) { - Ok(result) => result, - Err(NoSolution) => { - errors.push(FulfillmentError { - obligation: obligation.clone(), - code: match goal.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(_)) => { - FulfillmentErrorCode::CodeProjectionError( - // FIXME: This could be a `Sorts` if the term is a type - MismatchedProjectionTypes { err: TypeError::Mismatch }, - ) - } - ty::PredicateKind::AliasRelate(_, _, _) => { - FulfillmentErrorCode::CodeProjectionError( - MismatchedProjectionTypes { err: TypeError::Mismatch }, - ) - } - ty::PredicateKind::Subtype(pred) => { - let (a, b) = infcx.instantiate_binder_with_placeholders( - goal.predicate.kind().rebind((pred.a, pred.b)), - ); - let expected_found = ExpectedFound::new(true, a, b); - FulfillmentErrorCode::CodeSubtypeError( - expected_found, - TypeError::Sorts(expected_found), - ) - } - ty::PredicateKind::Coerce(pred) => { - let (a, b) = infcx.instantiate_binder_with_placeholders( - goal.predicate.kind().rebind((pred.a, pred.b)), - ); - let expected_found = ExpectedFound::new(false, a, b); - FulfillmentErrorCode::CodeSubtypeError( - expected_found, - TypeError::Sorts(expected_found), - ) - } - ty::PredicateKind::Clause(_) - | ty::PredicateKind::ObjectSafe(_) - | ty::PredicateKind::ClosureKind(_, _, _) - | ty::PredicateKind::Ambiguous => { - FulfillmentErrorCode::CodeSelectionError( - SelectionError::Unimplemented, - ) - } - ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::TypeWellFormedFromEnv(_) => { - bug!("unexpected goal: {goal:?}") - } - }, - root_obligation: obligation, - }); - continue; - } - }; + let (changed, certainty, nested_goals) = + match infcx.evaluate_root_goal(goal, GenerateProofTree::No).0 { + Ok(result) => result, + Err(NoSolution) => { + errors.push(FulfillmentError { + obligation: obligation.clone(), + code: match goal.predicate.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => { + FulfillmentErrorCode::CodeProjectionError( + // FIXME: This could be a `Sorts` if the term is a type + MismatchedProjectionTypes { err: TypeError::Mismatch }, + ) + } + ty::PredicateKind::AliasRelate(_, _, _) => { + FulfillmentErrorCode::CodeProjectionError( + MismatchedProjectionTypes { err: TypeError::Mismatch }, + ) + } + ty::PredicateKind::Subtype(pred) => { + let (a, b) = infcx.instantiate_binder_with_placeholders( + goal.predicate.kind().rebind((pred.a, pred.b)), + ); + let expected_found = ExpectedFound::new(true, a, b); + FulfillmentErrorCode::CodeSubtypeError( + expected_found, + TypeError::Sorts(expected_found), + ) + } + ty::PredicateKind::Coerce(pred) => { + let (a, b) = infcx.instantiate_binder_with_placeholders( + goal.predicate.kind().rebind((pred.a, pred.b)), + ); + let expected_found = ExpectedFound::new(false, a, b); + FulfillmentErrorCode::CodeSubtypeError( + expected_found, + TypeError::Sorts(expected_found), + ) + } + ty::PredicateKind::Clause(_) + | ty::PredicateKind::ObjectSafe(_) + | ty::PredicateKind::ClosureKind(_, _, _) + | ty::PredicateKind::Ambiguous => { + FulfillmentErrorCode::CodeSelectionError( + SelectionError::Unimplemented, + ) + } + ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::TypeWellFormedFromEnv(_) => { + bug!("unexpected goal: {goal:?}") + } + }, + root_obligation: obligation, + }); + continue; + } + }; // Push any nested goals that we get from unifying our canonical response // with our obligation onto the fulfillment context. self.obligations.extend(nested_goals.into_iter().map(|goal| { diff --git a/compiler/rustc_trait_selection/src/solve/inspect.rs b/compiler/rustc_trait_selection/src/solve/inspect.rs new file mode 100644 index 00000000000..6d7804a8fad --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/inspect.rs @@ -0,0 +1,373 @@ +use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::solve::inspect::{self, CacheHit, CandidateKind}; +use rustc_middle::traits::solve::{ + CanonicalInput, Certainty, Goal, IsNormalizesToHack, QueryInput, QueryResult, +}; +use rustc_middle::ty; + +pub mod dump; + +#[derive(Eq, PartialEq, Debug, Hash, HashStable)] +pub struct WipGoalEvaluation<'tcx> { + pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>, + pub canonicalized_goal: Option<CanonicalInput<'tcx>>, + + pub evaluation_steps: Vec<WipGoalEvaluationStep<'tcx>>, + + pub cache_hit: Option<CacheHit>, + pub is_normalizes_to_hack: IsNormalizesToHack, + pub returned_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>, + + pub result: Option<QueryResult<'tcx>>, +} + +impl<'tcx> WipGoalEvaluation<'tcx> { + pub fn finalize(self) -> inspect::GoalEvaluation<'tcx> { + inspect::GoalEvaluation { + uncanonicalized_goal: self.uncanonicalized_goal, + canonicalized_goal: self.canonicalized_goal.unwrap(), + kind: match self.cache_hit { + Some(hit) => inspect::GoalEvaluationKind::CacheHit(hit), + None => inspect::GoalEvaluationKind::Uncached { + revisions: self + .evaluation_steps + .into_iter() + .map(WipGoalEvaluationStep::finalize) + .collect(), + }, + }, + is_normalizes_to_hack: self.is_normalizes_to_hack, + returned_goals: self.returned_goals, + result: self.result.unwrap(), + } + } +} + +#[derive(Eq, PartialEq, Debug, Hash, HashStable)] +pub struct WipAddedGoalsEvaluation<'tcx> { + pub evaluations: Vec<Vec<WipGoalEvaluation<'tcx>>>, + pub result: Option<Result<Certainty, NoSolution>>, +} + +impl<'tcx> WipAddedGoalsEvaluation<'tcx> { + pub fn finalize(self) -> inspect::AddedGoalsEvaluation<'tcx> { + inspect::AddedGoalsEvaluation { + evaluations: self + .evaluations + .into_iter() + .map(|evaluations| { + evaluations.into_iter().map(WipGoalEvaluation::finalize).collect() + }) + .collect(), + result: self.result.unwrap(), + } + } +} + +#[derive(Eq, PartialEq, Debug, Hash, HashStable)] +pub struct WipGoalEvaluationStep<'tcx> { + pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>, + + pub nested_goal_evaluations: Vec<WipAddedGoalsEvaluation<'tcx>>, + pub candidates: Vec<WipGoalCandidate<'tcx>>, + + pub result: Option<QueryResult<'tcx>>, +} + +impl<'tcx> WipGoalEvaluationStep<'tcx> { + pub fn finalize(self) -> inspect::GoalEvaluationStep<'tcx> { + inspect::GoalEvaluationStep { + instantiated_goal: self.instantiated_goal, + nested_goal_evaluations: self + .nested_goal_evaluations + .into_iter() + .map(WipAddedGoalsEvaluation::finalize) + .collect(), + candidates: self.candidates.into_iter().map(WipGoalCandidate::finalize).collect(), + result: self.result.unwrap(), + } + } +} + +#[derive(Eq, PartialEq, Debug, Hash, HashStable)] +pub struct WipGoalCandidate<'tcx> { + pub nested_goal_evaluations: Vec<WipAddedGoalsEvaluation<'tcx>>, + pub candidates: Vec<WipGoalCandidate<'tcx>>, + pub kind: Option<CandidateKind<'tcx>>, +} + +impl<'tcx> WipGoalCandidate<'tcx> { + pub fn finalize(self) -> inspect::GoalCandidate<'tcx> { + inspect::GoalCandidate { + nested_goal_evaluations: self + .nested_goal_evaluations + .into_iter() + .map(WipAddedGoalsEvaluation::finalize) + .collect(), + candidates: self.candidates.into_iter().map(WipGoalCandidate::finalize).collect(), + kind: self.kind.unwrap(), + } + } +} + +#[derive(Debug)] +pub enum DebugSolver<'tcx> { + Root, + GoalEvaluation(WipGoalEvaluation<'tcx>), + AddedGoalsEvaluation(WipAddedGoalsEvaluation<'tcx>), + GoalEvaluationStep(WipGoalEvaluationStep<'tcx>), + GoalCandidate(WipGoalCandidate<'tcx>), +} + +impl<'tcx> From<WipGoalEvaluation<'tcx>> for DebugSolver<'tcx> { + fn from(g: WipGoalEvaluation<'tcx>) -> DebugSolver<'tcx> { + DebugSolver::GoalEvaluation(g) + } +} + +impl<'tcx> From<WipAddedGoalsEvaluation<'tcx>> for DebugSolver<'tcx> { + fn from(g: WipAddedGoalsEvaluation<'tcx>) -> DebugSolver<'tcx> { + DebugSolver::AddedGoalsEvaluation(g) + } +} + +impl<'tcx> From<WipGoalEvaluationStep<'tcx>> for DebugSolver<'tcx> { + fn from(g: WipGoalEvaluationStep<'tcx>) -> DebugSolver<'tcx> { + DebugSolver::GoalEvaluationStep(g) + } +} + +impl<'tcx> From<WipGoalCandidate<'tcx>> for DebugSolver<'tcx> { + fn from(g: WipGoalCandidate<'tcx>) -> DebugSolver<'tcx> { + DebugSolver::GoalCandidate(g) + } +} + +pub struct ProofTreeBuilder<'tcx> { + state: Option<Box<DebugSolver<'tcx>>>, +} + +impl<'tcx> ProofTreeBuilder<'tcx> { + fn new(state: impl Into<DebugSolver<'tcx>>) -> ProofTreeBuilder<'tcx> { + ProofTreeBuilder { state: Some(Box::new(state.into())) } + } + + fn as_mut(&mut self) -> Option<&mut DebugSolver<'tcx>> { + self.state.as_mut().map(|boxed| &mut **boxed) + } + + pub fn finalize(self) -> Option<inspect::GoalEvaluation<'tcx>> { + match *(self.state?) { + DebugSolver::GoalEvaluation(wip_goal_evaluation) => { + Some(wip_goal_evaluation.finalize()) + } + root => unreachable!("unexpected proof tree builder root node: {:?}", root), + } + } + + pub fn new_root() -> ProofTreeBuilder<'tcx> { + ProofTreeBuilder::new(DebugSolver::Root) + } + + pub fn new_noop() -> ProofTreeBuilder<'tcx> { + ProofTreeBuilder { state: None } + } + + pub fn is_noop(&self) -> bool { + self.state.is_none() + } + + pub fn new_goal_evaluation( + &mut self, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + is_normalizes_to_hack: IsNormalizesToHack, + ) -> ProofTreeBuilder<'tcx> { + if self.state.is_none() { + return ProofTreeBuilder { state: None }; + } + + ProofTreeBuilder::new(WipGoalEvaluation { + uncanonicalized_goal: goal, + canonicalized_goal: None, + evaluation_steps: vec![], + is_normalizes_to_hack, + cache_hit: None, + returned_goals: vec![], + result: None, + }) + } + + pub fn canonicalized_goal(&mut self, canonical_goal: CanonicalInput<'tcx>) { + if let Some(this) = self.as_mut() { + match this { + DebugSolver::GoalEvaluation(goal_evaluation) => { + assert_eq!(goal_evaluation.canonicalized_goal.replace(canonical_goal), None); + } + _ => unreachable!(), + } + } + } + + pub fn cache_hit(&mut self, cache_hit: CacheHit) { + if let Some(this) = self.as_mut() { + match this { + DebugSolver::GoalEvaluation(goal_evaluation) => { + assert_eq!(goal_evaluation.cache_hit.replace(cache_hit), None); + } + _ => unreachable!(), + }; + } + } + + pub fn returned_goals(&mut self, goals: &[Goal<'tcx, ty::Predicate<'tcx>>]) { + if let Some(this) = self.as_mut() { + match this { + DebugSolver::GoalEvaluation(evaluation) => { + assert!(evaluation.returned_goals.is_empty()); + evaluation.returned_goals.extend(goals); + } + _ => unreachable!(), + } + } + } + pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<'tcx>) { + if let Some(this) = self.as_mut() { + match (this, *goal_evaluation.state.unwrap()) { + ( + DebugSolver::AddedGoalsEvaluation(WipAddedGoalsEvaluation { + evaluations, .. + }), + DebugSolver::GoalEvaluation(goal_evaluation), + ) => evaluations.last_mut().unwrap().push(goal_evaluation), + (this @ DebugSolver::Root, goal_evaluation) => *this = goal_evaluation, + _ => unreachable!(), + } + } + } + + pub fn new_goal_evaluation_step( + &mut self, + instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>, + ) -> ProofTreeBuilder<'tcx> { + if self.state.is_none() { + return ProofTreeBuilder { state: None }; + } + + ProofTreeBuilder::new(WipGoalEvaluationStep { + instantiated_goal, + nested_goal_evaluations: vec![], + candidates: vec![], + result: None, + }) + } + pub fn goal_evaluation_step(&mut self, goal_eval_step: ProofTreeBuilder<'tcx>) { + if let Some(this) = self.as_mut() { + match (this, *goal_eval_step.state.unwrap()) { + (DebugSolver::GoalEvaluation(goal_eval), DebugSolver::GoalEvaluationStep(step)) => { + goal_eval.evaluation_steps.push(step); + } + _ => unreachable!(), + } + } + } + + pub fn new_goal_candidate(&mut self) -> ProofTreeBuilder<'tcx> { + if self.state.is_none() { + return ProofTreeBuilder { state: None }; + } + + ProofTreeBuilder::new(WipGoalCandidate { + nested_goal_evaluations: vec![], + candidates: vec![], + kind: None, + }) + } + + pub fn candidate_kind(&mut self, candidate_kind: CandidateKind<'tcx>) { + if let Some(this) = self.as_mut() { + match this { + DebugSolver::GoalCandidate(this) => { + assert_eq!(this.kind.replace(candidate_kind), None) + } + _ => unreachable!(), + } + } + } + + pub fn goal_candidate(&mut self, candidate: ProofTreeBuilder<'tcx>) { + if let Some(this) = self.as_mut() { + match (this, *candidate.state.unwrap()) { + ( + DebugSolver::GoalCandidate(WipGoalCandidate { candidates, .. }) + | DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { candidates, .. }), + DebugSolver::GoalCandidate(candidate), + ) => candidates.push(candidate), + _ => unreachable!(), + } + } + } + + pub fn new_evaluate_added_goals(&mut self) -> ProofTreeBuilder<'tcx> { + if self.state.is_none() { + return ProofTreeBuilder { state: None }; + } + + ProofTreeBuilder::new(WipAddedGoalsEvaluation { evaluations: vec![], result: None }) + } + + pub fn evaluate_added_goals_loop_start(&mut self) { + if let Some(this) = self.as_mut() { + match this { + DebugSolver::AddedGoalsEvaluation(this) => { + this.evaluations.push(vec![]); + } + _ => unreachable!(), + } + } + } + + pub fn eval_added_goals_result(&mut self, result: Result<Certainty, NoSolution>) { + if let Some(this) = self.as_mut() { + match this { + DebugSolver::AddedGoalsEvaluation(this) => { + assert_eq!(this.result.replace(result), None); + } + _ => unreachable!(), + } + } + } + + pub fn added_goals_evaluation(&mut self, goals_evaluation: ProofTreeBuilder<'tcx>) { + if let Some(this) = self.as_mut() { + match (this, *goals_evaluation.state.unwrap()) { + ( + DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { + nested_goal_evaluations, + .. + }) + | DebugSolver::GoalCandidate(WipGoalCandidate { + nested_goal_evaluations, .. + }), + DebugSolver::AddedGoalsEvaluation(added_goals_evaluation), + ) => nested_goal_evaluations.push(added_goals_evaluation), + _ => unreachable!(), + } + } + } + + pub fn query_result(&mut self, result: QueryResult<'tcx>) { + if let Some(this) = self.as_mut() { + match this { + DebugSolver::GoalEvaluation(goal_evaluation) => { + assert_eq!(goal_evaluation.result.replace(result), None); + } + DebugSolver::GoalEvaluationStep(evaluation_step) => { + assert_eq!(evaluation_step.result.replace(result), None); + } + DebugSolver::Root + | DebugSolver::AddedGoalsEvaluation(_) + | DebugSolver::GoalCandidate(_) => unreachable!(), + } + } + } +} diff --git a/compiler/rustc_trait_selection/src/solve/inspect/dump.rs b/compiler/rustc_trait_selection/src/solve/inspect/dump.rs new file mode 100644 index 00000000000..b755ee86215 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/inspect/dump.rs @@ -0,0 +1,5 @@ +use rustc_middle::traits::solve::inspect::GoalEvaluation; + +pub fn print_tree(tree: &GoalEvaluation<'_>) { + debug!(?tree); +} diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index a30a14df80b..49fecedc0ca 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -25,6 +25,7 @@ mod assembly; mod canonicalize; mod eval_ctxt; mod fulfill; +pub mod inspect; mod opaques; mod project_goals; mod search_graph; diff --git a/compiler/rustc_trait_selection/src/solve/opaques.rs b/compiler/rustc_trait_selection/src/solve/opaques.rs index 538c16c8ce2..16194f5ad69 100644 --- a/compiler/rustc_trait_selection/src/solve/opaques.rs +++ b/compiler/rustc_trait_selection/src/solve/opaques.rs @@ -20,8 +20,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let Some(opaque_ty_def_id) = opaque_ty.def_id.as_local() else { return Err(NoSolution); }; - let opaque_ty = - ty::OpaqueTypeKey { def_id: opaque_ty_def_id, substs: opaque_ty.substs }; // FIXME: at some point we should call queries without defining // new opaque types but having the existing opaque type definitions. // This will require moving this below "Prefer opaques registered already". @@ -41,7 +39,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { Ok(()) => {} } // Prefer opaques registered already. - let matches = self.unify_existing_opaque_tys(goal.param_env, opaque_ty, expected); + let opaque_type_key = + ty::OpaqueTypeKey { def_id: opaque_ty_def_id, substs: opaque_ty.substs }; + let matches = + self.unify_existing_opaque_tys(goal.param_env, opaque_type_key, expected); if !matches.is_empty() { if let Some(response) = self.try_merge_responses(&matches) { return Ok(response); @@ -50,11 +51,24 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } // Otherwise, define a new opaque type - self.insert_hidden_type(opaque_ty, goal.param_env, expected)?; - self.add_item_bounds_for_hidden_type(opaque_ty, goal.param_env, expected); + self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?; + self.add_item_bounds_for_hidden_type( + opaque_ty.def_id, + opaque_ty.substs, + goal.param_env, + expected, + ); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } (Reveal::UserFacing, SolverMode::Coherence) => { + // An impossible opaque type bound is the only way this goal will fail + // e.g. assigning `impl Copy := NotCopy` + self.add_item_bounds_for_hidden_type( + opaque_ty.def_id, + opaque_ty.substs, + goal.param_env, + expected, + ); self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } (Reveal::All, _) => { diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index e9600968f48..cbea8009f02 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -9,6 +9,7 @@ use rustc_hir::LangItem; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::specialization_graph::LeafDef; use rustc_infer::traits::Reveal; +use rustc_middle::traits::solve::inspect::CandidateKind; use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult}; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::ProjectionPredicate; @@ -106,24 +107,31 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { fn probe_and_match_goal_against_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - assumption: ty::Binder<'tcx, ty::Clause<'tcx>>, + assumption: ty::Clause<'tcx>, then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>, ) -> QueryResult<'tcx> { - if let Some(projection_pred) = assumption.as_projection_clause() - && projection_pred.projection_def_id() == goal.predicate.def_id() - { - ecx.probe(|ecx| { - let assumption_projection_pred = - ecx.instantiate_binder_with_infer(projection_pred); - ecx.eq( - goal.param_env, - goal.predicate.projection_ty, - assumption_projection_pred.projection_ty, - )?; - ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term) - .expect("expected goal term to be fully unconstrained"); - then(ecx) - }) + if let Some(projection_pred) = assumption.as_projection_clause() { + if projection_pred.projection_def_id() == goal.predicate.def_id() { + ecx.probe(|r| CandidateKind::Candidate { name: "assumption".into(), result: *r }) + .enter(|ecx| { + let assumption_projection_pred = + ecx.instantiate_binder_with_infer(projection_pred); + ecx.eq( + goal.param_env, + goal.predicate.projection_ty, + assumption_projection_pred.projection_ty, + )?; + ecx.eq( + goal.param_env, + goal.predicate.term, + assumption_projection_pred.term, + ) + .expect("expected goal term to be fully unconstrained"); + then(ecx) + }) + } else { + Err(NoSolution) + } } else { Err(NoSolution) } @@ -143,87 +151,90 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { return Err(NoSolution); } - ecx.probe(|ecx| { - let impl_substs = ecx.fresh_substs_for_item(impl_def_id); - let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); - - ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?; - - let where_clause_bounds = tcx - .predicates_of(impl_def_id) - .instantiate(tcx, impl_substs) - .predicates - .into_iter() - .map(|pred| goal.with(tcx, pred)); - ecx.add_goals(where_clause_bounds); - - // In case the associated item is hidden due to specialization, we have to - // return ambiguity this would otherwise be incomplete, resulting in - // unsoundness during coherence (#105782). - let Some(assoc_def) = fetch_eligible_assoc_item_def( - ecx, - goal.param_env, - goal_trait_ref, - goal.predicate.def_id(), - impl_def_id - )? else { - return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); - }; + ecx.probe( + |r| CandidateKind::Candidate { name: "impl".into(), result: *r }).enter( + |ecx| { + let impl_substs = ecx.fresh_substs_for_item(impl_def_id); + let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); + + ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?; + + let where_clause_bounds = tcx + .predicates_of(impl_def_id) + .instantiate(tcx, impl_substs) + .predicates + .into_iter() + .map(|pred| goal.with(tcx, pred)); + ecx.add_goals(where_clause_bounds); + + // In case the associated item is hidden due to specialization, we have to + // return ambiguity this would otherwise be incomplete, resulting in + // unsoundness during coherence (#105782). + let Some(assoc_def) = fetch_eligible_assoc_item_def( + ecx, + goal.param_env, + goal_trait_ref, + goal.predicate.def_id(), + impl_def_id + )? else { + return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); + }; + + if !assoc_def.item.defaultness(tcx).has_value() { + let guar = tcx.sess.delay_span_bug( + tcx.def_span(assoc_def.item.def_id), + "missing value for assoc item in impl", + ); + let error_term = match assoc_def.item.kind { + ty::AssocKind::Const => tcx + .const_error( + tcx.type_of(goal.predicate.def_id()) + .subst(tcx, goal.predicate.projection_ty.substs), + guar, + ) + .into(), + ty::AssocKind::Type => tcx.ty_error(guar).into(), + ty::AssocKind::Fn => unreachable!(), + }; + ecx.eq(goal.param_env, goal.predicate.term, error_term) + .expect("expected goal term to be fully unconstrained"); + return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); + } - if !assoc_def.item.defaultness(tcx).has_value() { - let guar = tcx.sess.delay_span_bug( - tcx.def_span(assoc_def.item.def_id), - "missing value for assoc item in impl", + // Getting the right substitutions here is complex, e.g. given: + // - a goal `<Vec<u32> as Trait<i32>>::Assoc<u64>` + // - the applicable impl `impl<T> Trait<i32> for Vec<T>` + // - and the impl which defines `Assoc` being `impl<T, U> Trait<U> for Vec<T>` + // + // We first rebase the goal substs onto the impl, going from `[Vec<u32>, i32, u64]` + // to `[u32, u64]`. + // + // And then map these substs to the substs of the defining impl of `Assoc`, going + // from `[u32, u64]` to `[u32, i32, u64]`. + let impl_substs_with_gat = goal.predicate.projection_ty.substs.rebase_onto( + tcx, + goal_trait_ref.def_id, + impl_substs, + ); + let substs = ecx.translate_substs( + goal.param_env, + impl_def_id, + impl_substs_with_gat, + assoc_def.defining_node, ); - let error_term = match assoc_def.item.kind { - ty::AssocKind::Const => tcx - .const_error( - tcx.type_of(goal.predicate.def_id()) - .subst(tcx, goal.predicate.projection_ty.substs), - guar, - ) - .into(), - ty::AssocKind::Type => tcx.ty_error(guar).into(), - ty::AssocKind::Fn => unreachable!(), - }; - ecx.eq(goal.param_env, goal.predicate.term, error_term) - .expect("expected goal term to be fully unconstrained"); - return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); - } - // Getting the right substitutions here is complex, e.g. given: - // - a goal `<Vec<u32> as Trait<i32>>::Assoc<u64>` - // - the applicable impl `impl<T> Trait<i32> for Vec<T>` - // - and the impl which defines `Assoc` being `impl<T, U> Trait<U> for Vec<T>` - // - // We first rebase the goal substs onto the impl, going from `[Vec<u32>, i32, u64]` - // to `[u32, u64]`. - // - // And then map these substs to the substs of the defining impl of `Assoc`, going - // from `[u32, u64]` to `[u32, i32, u64]`. - let impl_substs_with_gat = goal.predicate.projection_ty.substs.rebase_onto( - tcx, - goal_trait_ref.def_id, - impl_substs, - ); - let substs = ecx.translate_substs( - goal.param_env, - impl_def_id, - impl_substs_with_gat, - assoc_def.defining_node, - ); - - // Finally we construct the actual value of the associated type. - let term = match assoc_def.item.kind { - ty::AssocKind::Type => tcx.type_of(assoc_def.item.def_id).map_bound(|ty| ty.into()), - ty::AssocKind::Const => bug!("associated const projection is not supported yet"), - ty::AssocKind::Fn => unreachable!("we should never project to a fn"), - }; + // Finally we construct the actual value of the associated type. + let term = match assoc_def.item.kind { + ty::AssocKind::Type => tcx.type_of(assoc_def.item.def_id).map_bound(|ty| ty.into()), + ty::AssocKind::Const => bug!("associated const projection is not supported yet"), + ty::AssocKind::Fn => unreachable!("we should never project to a fn"), + }; - ecx.eq(goal.param_env, goal.predicate.term, term.subst(tcx, substs)) - .expect("expected goal term to be fully unconstrained"); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) + ecx.eq(goal.param_env, goal.predicate.term, term.subst(tcx, substs)) + .expect("expected goal term to be fully unconstrained"); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }, + ) } fn consider_auto_trait_candidate( @@ -318,53 +329,69 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { let tcx = ecx.tcx(); - ecx.probe(|ecx| { - let metadata_ty = match goal.predicate.self_ty().kind() { - ty::Bool - | ty::Char - | ty::Int(..) - | ty::Uint(..) - | ty::Float(..) - | ty::Array(..) - | ty::RawPtr(..) - | ty::Ref(..) - | ty::FnDef(..) - | ty::FnPtr(..) - | ty::Closure(..) - | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) - | ty::Generator(..) - | ty::GeneratorWitness(..) - | ty::GeneratorWitnessMIR(..) - | ty::Never - | ty::Foreign(..) => tcx.types.unit, - - ty::Error(e) => tcx.ty_error(*e), - - ty::Str | ty::Slice(_) => tcx.types.usize, - - ty::Dynamic(_, _, _) => { - let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None); - tcx.type_of(dyn_metadata) - .subst(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())]) - } + ecx.probe(|r| CandidateKind::Candidate { name: "builtin pointee".into(), result: *r }) + .enter(|ecx| { + let metadata_ty = match goal.predicate.self_ty().kind() { + ty::Bool + | ty::Char + | ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::Array(..) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Closure(..) + | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) + | ty::Never + | ty::Foreign(..) => tcx.types.unit, + + ty::Error(e) => tcx.ty_error(*e), + + ty::Str | ty::Slice(_) => tcx.types.usize, + + ty::Dynamic(_, _, _) => { + let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None); + tcx.type_of(dyn_metadata) + .subst(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())]) + } - ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => { - // FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints. - let sized_predicate = ty::TraitRef::from_lang_item( - tcx, - LangItem::Sized, - DUMMY_SP, - [ty::GenericArg::from(goal.predicate.self_ty())], - ); - ecx.add_goal(goal.with(tcx, sized_predicate)); - tcx.types.unit - } + ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => { + // FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints. + let sized_predicate = ty::TraitRef::from_lang_item( + tcx, + LangItem::Sized, + DUMMY_SP, + [ty::GenericArg::from(goal.predicate.self_ty())], + ); + ecx.add_goal(goal.with(tcx, sized_predicate)); + tcx.types.unit + } + + ty::Adt(def, substs) if def.is_struct() => { + match def.non_enum_variant().fields.raw.last() { + None => tcx.types.unit, + Some(field_def) => { + let self_ty = field_def.ty(tcx, substs); + ecx.add_goal(goal.with( + tcx, + ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)), + )); + return ecx.evaluate_added_goals_and_make_canonical_response( + Certainty::Yes, + ); + } + } + } + ty::Adt(_, _) => tcx.types.unit, - ty::Adt(def, substs) if def.is_struct() => { - match def.non_enum_variant().fields.raw.last() { + ty::Tuple(elements) => match elements.last() { None => tcx.types.unit, - Some(field_def) => { - let self_ty = field_def.ty(tcx, substs); + Some(&self_ty) => { ecx.add_goal(goal.with( tcx, ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)), @@ -372,35 +399,21 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { return ecx .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); } - } - } - ty::Adt(_, _) => tcx.types.unit, - - ty::Tuple(elements) => match elements.last() { - None => tcx.types.unit, - Some(&self_ty) => { - ecx.add_goal(goal.with( - tcx, - ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)), - )); - return ecx - .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); - } - }, - - ty::Infer( - ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_), - ) - | ty::Bound(..) => bug!( - "unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`", - goal.predicate.self_ty() - ), - }; + }, + + ty::Infer( + ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_), + ) + | ty::Bound(..) => bug!( + "unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`", + goal.predicate.self_ty() + ), + }; - ecx.eq(goal.param_env, goal.predicate.term, metadata_ty.into()) - .expect("expected goal term to be fully unconstrained"); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) + ecx.eq(goal.param_env, goal.predicate.term, metadata_ty.into()) + .expect("expected goal term to be fully unconstrained"); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } fn consider_builtin_future_candidate( @@ -535,7 +548,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ), }; - ecx.probe(|ecx| { + ecx.probe(|r| CandidateKind::Candidate { + name: "builtin discriminant kind".into(), + result: *r, + }) + .enter(|ecx| { ecx.eq(goal.param_env, goal.predicate.term, discriminant_ty.into()) .expect("expected goal term to be fully unconstrained"); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index 19e4b23009a..d167ee46b39 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -2,6 +2,7 @@ mod cache; mod overflow; pub(super) use overflow::OverflowHandler; +use rustc_middle::traits::solve::inspect::CacheHit; use self::cache::ProvisionalEntry; use cache::ProvisionalCache; @@ -12,6 +13,7 @@ use rustc_middle::traits::solve::{CanonicalInput, Certainty, MaybeCause, QueryRe use rustc_middle::ty::TyCtxt; use std::{collections::hash_map::Entry, mem}; +use super::inspect::ProofTreeBuilder; use super::SolverMode; rustc_index::newtype_index! { @@ -88,11 +90,12 @@ impl<'tcx> SearchGraph<'tcx> { /// Tries putting the new goal on the stack, returning an error if it is already cached. /// /// This correctly updates the provisional cache if there is a cycle. - #[instrument(level = "debug", skip(self, tcx), ret)] + #[instrument(level = "debug", skip(self, tcx, inspect), ret)] fn try_push_stack( &mut self, tcx: TyCtxt<'tcx>, input: CanonicalInput<'tcx>, + inspect: &mut ProofTreeBuilder<'tcx>, ) -> Result<(), QueryResult<'tcx>> { // Look at the provisional cache to check for cycles. let cache = &mut self.provisional_cache; @@ -119,6 +122,8 @@ impl<'tcx> SearchGraph<'tcx> { // Finally we can return either the provisional response for that goal if we have a // coinductive cycle or an ambiguous result if the cycle is inductive. Entry::Occupied(entry_index) => { + inspect.cache_hit(CacheHit::Provisional); + let entry_index = *entry_index.get(); let stack_depth = cache.depth(entry_index); @@ -205,16 +210,18 @@ impl<'tcx> SearchGraph<'tcx> { &mut self, tcx: TyCtxt<'tcx>, canonical_input: CanonicalInput<'tcx>, - mut loop_body: impl FnMut(&mut Self) -> QueryResult<'tcx>, + inspect: &mut ProofTreeBuilder<'tcx>, + mut loop_body: impl FnMut(&mut Self, &mut ProofTreeBuilder<'tcx>) -> QueryResult<'tcx>, ) -> QueryResult<'tcx> { if self.should_use_global_cache() { if let Some(result) = tcx.new_solver_evaluation_cache.get(&canonical_input, tcx) { debug!(?canonical_input, ?result, "cache hit"); + inspect.cache_hit(CacheHit::Global); return result; } } - match self.try_push_stack(tcx, canonical_input) { + match self.try_push_stack(tcx, canonical_input, inspect) { Ok(()) => {} // Our goal is already on the stack, eager return. Err(response) => return response, @@ -231,7 +238,7 @@ impl<'tcx> SearchGraph<'tcx> { result }, |this| { - let result = loop_body(this); + let result = loop_body(this, inspect); this.try_finalize_goal(canonical_input, result).then(|| result) }, ) diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 279fc1229d4..18fec6d9c89 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -6,6 +6,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{LangItem, Movability}; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::util::supertraits; +use rustc_middle::traits::solve::inspect::CandidateKind; use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult}; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; @@ -61,7 +62,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { }, }; - ecx.probe(|ecx| { + ecx.probe(|r| CandidateKind::Candidate { name: "impl".into(), result: *r }).enter(|ecx| { let impl_substs = ecx.fresh_substs_for_item(impl_def_id); let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); @@ -81,24 +82,27 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn probe_and_match_goal_against_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - assumption: ty::Binder<'tcx, ty::Clause<'tcx>>, + assumption: ty::Clause<'tcx>, then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>, ) -> QueryResult<'tcx> { - if let Some(trait_clause) = assumption.as_trait_clause() - && trait_clause.def_id() == goal.predicate.def_id() - && trait_clause.polarity() == goal.predicate.polarity - { - // FIXME: Constness - ecx.probe(|ecx| { - let assumption_trait_pred = - ecx.instantiate_binder_with_infer(trait_clause); - ecx.eq( - goal.param_env, - goal.predicate.trait_ref, - assumption_trait_pred.trait_ref, - )?; - then(ecx) - }) + if let Some(trait_clause) = assumption.as_trait_clause() { + if trait_clause.def_id() == goal.predicate.def_id() + && trait_clause.polarity() == goal.predicate.polarity + { + // FIXME: Constness + ecx.probe(|r| CandidateKind::Candidate { name: "assumption".into(), result: *r }) + .enter(|ecx| { + let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause); + ecx.eq( + goal.param_env, + goal.predicate.trait_ref, + assumption_trait_pred.trait_ref, + )?; + then(ecx) + }) + } else { + Err(NoSolution) + } } else { Err(NoSolution) } @@ -132,13 +136,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let tcx = ecx.tcx(); - ecx.probe(|ecx| { - let nested_obligations = tcx - .predicates_of(goal.predicate.def_id()) - .instantiate(tcx, goal.predicate.trait_ref.substs); - ecx.add_goals(nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p))); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) + ecx.probe(|r| CandidateKind::Candidate { name: "trait alias".into(), result: *r }).enter( + |ecx| { + let nested_obligations = tcx + .predicates_of(goal.predicate.def_id()) + .instantiate(tcx, goal.predicate.trait_ref.substs); + ecx.add_goals(nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p))); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }, + ) } fn consider_builtin_sized_candidate( @@ -344,109 +350,115 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { if b_ty.is_ty_var() { return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); } - ecx.probe(|ecx| { - match (a_ty.kind(), b_ty.kind()) { - // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b` - (&ty::Dynamic(_, _, ty::Dyn), &ty::Dynamic(_, _, ty::Dyn)) => { - // Dyn upcasting is handled separately, since due to upcasting, - // when there are two supertraits that differ by substs, we - // may return more than one query response. - Err(NoSolution) - } - // `T` -> `dyn Trait` unsizing - (_, &ty::Dynamic(data, region, ty::Dyn)) => { - // Can only unsize to an object-safe type - if data - .principal_def_id() - .is_some_and(|def_id| !tcx.check_is_object_safe(def_id)) - { - return Err(NoSolution); + ecx.probe(|r| CandidateKind::Candidate { name: "builtin unsize".into(), result: *r }).enter( + |ecx| { + match (a_ty.kind(), b_ty.kind()) { + // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b` + (&ty::Dynamic(_, _, ty::Dyn), &ty::Dynamic(_, _, ty::Dyn)) => { + // Dyn upcasting is handled separately, since due to upcasting, + // when there are two supertraits that differ by substs, we + // may return more than one query response. + Err(NoSolution) } - - let Some(sized_def_id) = tcx.lang_items().sized_trait() else { + // `T` -> `dyn Trait` unsizing + (_, &ty::Dynamic(data, region, ty::Dyn)) => { + // Can only unsize to an object-safe type + if data + .principal_def_id() + .is_some_and(|def_id| !tcx.check_is_object_safe(def_id)) + { + return Err(NoSolution); + } + + let Some(sized_def_id) = tcx.lang_items().sized_trait() else { return Err(NoSolution); }; - // Check that the type implements all of the predicates of the def-id. - // (i.e. the principal, all of the associated types match, and any auto traits) - ecx.add_goals( - data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))), - ); - // The type must be Sized to be unsized. - ecx.add_goal(goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty]))); - // The type must outlive the lifetime of the `dyn` we're unsizing into. - ecx.add_goal( - goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region))), - ); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } - // `[T; n]` -> `[T]` unsizing - (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => { - // We just require that the element type stays the same - ecx.eq(goal.param_env, a_elem_ty, b_elem_ty)?; - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } - // Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>` - (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs)) - if a_def.is_struct() && a_def.did() == b_def.did() => - { - let unsizing_params = tcx.unsizing_params_for_adt(a_def.did()); - // We must be unsizing some type parameters. This also implies - // that the struct has a tail field. - if unsizing_params.is_empty() { - return Err(NoSolution); + // Check that the type implements all of the predicates of the def-id. + // (i.e. the principal, all of the associated types match, and any auto traits) + ecx.add_goals( + data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))), + ); + // The type must be Sized to be unsized. + ecx.add_goal(goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty]))); + // The type must outlive the lifetime of the `dyn` we're unsizing into. + ecx.add_goal( + goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region))), + ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } - - let tail_field = a_def - .non_enum_variant() - .fields - .raw - .last() - .expect("expected unsized ADT to have a tail field"); - let tail_field_ty = tcx.type_of(tail_field.did); - - let a_tail_ty = tail_field_ty.subst(tcx, a_substs); - let b_tail_ty = tail_field_ty.subst(tcx, b_substs); - - // Substitute just the unsizing params from B into A. The type after - // this substitution must be equal to B. This is so we don't unsize - // unrelated type parameters. - let new_a_substs = - tcx.mk_substs_from_iter(a_substs.iter().enumerate().map(|(i, a)| { - if unsizing_params.contains(i as u32) { b_substs[i] } else { a } - })); - let unsized_a_ty = tcx.mk_adt(a_def, new_a_substs); - - // Finally, we require that `TailA: Unsize<TailB>` for the tail field - // types. - ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; - ecx.add_goal(goal.with( - tcx, - ty::TraitRef::new(tcx, goal.predicate.def_id(), [a_tail_ty, b_tail_ty]), - )); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } - // Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>` - (&ty::Tuple(a_tys), &ty::Tuple(b_tys)) - if a_tys.len() == b_tys.len() && !a_tys.is_empty() => - { - let (a_last_ty, a_rest_tys) = a_tys.split_last().unwrap(); - let b_last_ty = b_tys.last().unwrap(); - - // Substitute just the tail field of B., and require that they're equal. - let unsized_a_ty = - tcx.mk_tup_from_iter(a_rest_tys.iter().chain([b_last_ty]).copied()); - ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; - - // Similar to ADTs, require that the rest of the fields are equal. - ecx.add_goal(goal.with( - tcx, - ty::TraitRef::new(tcx, goal.predicate.def_id(), [*a_last_ty, *b_last_ty]), - )); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + // `[T; n]` -> `[T]` unsizing + (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => { + // We just require that the element type stays the same + ecx.eq(goal.param_env, a_elem_ty, b_elem_ty)?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + // Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>` + (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs)) + if a_def.is_struct() && a_def.did() == b_def.did() => + { + let unsizing_params = tcx.unsizing_params_for_adt(a_def.did()); + // We must be unsizing some type parameters. This also implies + // that the struct has a tail field. + if unsizing_params.is_empty() { + return Err(NoSolution); + } + + let tail_field = a_def + .non_enum_variant() + .fields + .raw + .last() + .expect("expected unsized ADT to have a tail field"); + let tail_field_ty = tcx.type_of(tail_field.did); + + let a_tail_ty = tail_field_ty.subst(tcx, a_substs); + let b_tail_ty = tail_field_ty.subst(tcx, b_substs); + + // Substitute just the unsizing params from B into A. The type after + // this substitution must be equal to B. This is so we don't unsize + // unrelated type parameters. + let new_a_substs = + tcx.mk_substs_from_iter(a_substs.iter().enumerate().map(|(i, a)| { + if unsizing_params.contains(i as u32) { b_substs[i] } else { a } + })); + let unsized_a_ty = tcx.mk_adt(a_def, new_a_substs); + + // Finally, we require that `TailA: Unsize<TailB>` for the tail field + // types. + ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; + ecx.add_goal(goal.with( + tcx, + ty::TraitRef::new(tcx, goal.predicate.def_id(), [a_tail_ty, b_tail_ty]), + )); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + // Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>` + (&ty::Tuple(a_tys), &ty::Tuple(b_tys)) + if a_tys.len() == b_tys.len() && !a_tys.is_empty() => + { + let (a_last_ty, a_rest_tys) = a_tys.split_last().unwrap(); + let b_last_ty = b_tys.last().unwrap(); + + // Substitute just the tail field of B., and require that they're equal. + let unsized_a_ty = + tcx.mk_tup_from_iter(a_rest_tys.iter().chain([b_last_ty]).copied()); + ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; + + // Similar to ADTs, require that the rest of the fields are equal. + ecx.add_goal(goal.with( + tcx, + ty::TraitRef::new( + tcx, + goal.predicate.def_id(), + [*a_last_ty, *b_last_ty], + ), + )); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + _ => Err(NoSolution), } - _ => Err(NoSolution), - } - }) + }, + ) } fn consider_builtin_dyn_upcast_candidates( @@ -476,7 +488,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } let mut unsize_dyn_to_principal = |principal: Option<ty::PolyExistentialTraitRef<'tcx>>| { - ecx.probe(|ecx| -> Result<_, NoSolution> { + ecx.probe(|r| CandidateKind::Candidate { + name: "upcast dyn to principle".into(), + result: *r, + }) + .enter(|ecx| -> Result<_, NoSolution> { // Require that all of the trait predicates from A match B, except for // the auto traits. We do this by constructing a new A type with B's // auto traits, and equating these types. @@ -698,20 +714,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, TraitPredicate<'tcx>>, constituent_tys: impl Fn(&EvalCtxt<'_, 'tcx>, Ty<'tcx>) -> Result<Vec<Ty<'tcx>>, NoSolution>, ) -> QueryResult<'tcx> { - self.probe(|ecx| { - ecx.add_goals( - constituent_tys(ecx, goal.predicate.self_ty())? - .into_iter() - .map(|ty| { - goal.with( - ecx.tcx(), - ty::Binder::dummy(goal.predicate.with_self_ty(ecx.tcx(), ty)), - ) - }) - .collect::<Vec<_>>(), - ); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) + self.probe(|r| CandidateKind::Candidate { name: "constituent tys".into(), result: *r }) + .enter(|ecx| { + ecx.add_goals( + constituent_tys(ecx, goal.predicate.self_ty())? + .into_iter() + .map(|ty| { + goal.with( + ecx.tcx(), + ty::Binder::dummy(goal.predicate.with_self_ty(ecx.tcx(), ty)), + ) + }) + .collect::<Vec<_>>(), + ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } #[instrument(level = "debug", skip(self))] diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 56fde8cd70c..71557e8930d 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -400,8 +400,8 @@ impl<'tcx> AutoTraitFinder<'tcx> { let mut should_add_new = true; user_computed_preds.retain(|&old_pred| { if let ( - ty::PredicateKind::Clause(ty::Clause::Trait(new_trait)), - ty::PredicateKind::Clause(ty::Clause::Trait(old_trait)), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(new_trait)), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(old_trait)), ) = (new_pred.kind().skip_binder(), old_pred.kind().skip_binder()) { if new_trait.def_id() == old_trait.def_id() { @@ -621,14 +621,14 @@ impl<'tcx> AutoTraitFinder<'tcx> { let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(p)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(p)) => { // Add this to `predicates` so that we end up calling `select` // with it. If this predicate ends up being unimplemented, // then `evaluate_predicates` will handle adding it the `ParamEnv` // if possible. predicates.push_back(bound_predicate.rebind(p)); } - ty::PredicateKind::Clause(ty::Clause::Projection(p)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => { let p = bound_predicate.rebind(p); debug!( "evaluate_nested_obligations: examining projection predicate {:?}", @@ -758,11 +758,11 @@ impl<'tcx> AutoTraitFinder<'tcx> { } } } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(binder)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(binder)) => { let binder = bound_predicate.rebind(binder); selcx.infcx.region_outlives_predicate(&dummy_cause, binder) } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(binder)) => { + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(binder)) => { let binder = bound_predicate.rebind(binder); match ( binder.no_bound_vars(), @@ -826,14 +826,14 @@ impl<'tcx> AutoTraitFinder<'tcx> { // we start out with a `ParamEnv` with no inference variables, // and these don't correspond to adding any new bounds to // the `ParamEnv`. - ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) // FIXME(generic_const_exprs): you can absolutely add this as a where clauses - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::Coerce(..) => {} ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("predicate should only exist in the environment: {bound_predicate:?}") diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index f8789b554b1..f9f242d29f6 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -207,7 +207,7 @@ fn satisfied_from_param_env<'tcx>( for pred in param_env.caller_bounds() { match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(ce)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ce)) => { let b_ct = tcx.expand_abstract_consts(ce); let mut v = Visitor { ct, infcx, param_env, single_match }; let _ = b_ct.visit_with(&mut v); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs index 7ab652761a4..1351d9bb257 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs @@ -84,7 +84,7 @@ pub fn recompute_applicable_impls<'tcx>( tcx.predicates_of(obligation.cause.body_id.to_def_id()).instantiate_identity(tcx); for (pred, span) in elaborate(tcx, predicates.into_iter()) { let kind = pred.kind(); - if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = kind.skip_binder() + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) = kind.skip_binder() && param_env_candidate_may_apply(kind.rebind(trait_pred)) { if kind.rebind(trait_pred.trait_ref) == ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_pred.def_id())) { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 398ec28a426..557341f7ac8 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -678,7 +678,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let bound_predicate = obligation.predicate.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => { let trait_predicate = bound_predicate.rebind(trait_predicate); let mut trait_predicate = self.resolve_vars_if_possible(trait_predicate); @@ -1021,8 +1021,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { span_bug!(span, "coerce requirement gave wrong error: `{:?}`", predicate) } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) => { span_bug!( span, "outlives clauses should not error outside borrowck. obligation: `{:?}`", @@ -1030,7 +1030,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) } - ty::PredicateKind::Clause(ty::Clause::Projection(..)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) => { span_bug!( span, "projection clauses should be implied from elsewhere. obligation: `{:?}`", @@ -1048,7 +1048,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.report_closure_error(&obligation, closure_def_id, found_kind, kind) } - ty::PredicateKind::Clause(ty::Clause::WellFormed(ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => { + let ty = self.resolve_vars_if_possible(ty); match self.tcx.sess.opts.unstable_opts.trait_solver { TraitSolver::Classic => { // WF predicates cannot themselves make @@ -1069,7 +1070,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) => { // Errors for `ConstEvaluatable` predicates show up as // `SelectionError::ConstEvalFailure`, // not `Unimplemented`. @@ -1103,7 +1104,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { "AliasRelate predicate should never be the predicate cause of a SelectionError" ), - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { let mut diag = self.tcx.sess.struct_span_err( span, format!("the constant `{}` is not of type `{}`", ct, ty), @@ -1494,8 +1495,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let bound_error = error.kind(); let (cond, error) = match (cond.kind().skip_binder(), bound_error.skip_binder()) { ( - ty::PredicateKind::Clause(ty::Clause::Trait(..)), - ty::PredicateKind::Clause(ty::Clause::Trait(error)), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(error)), ) => (cond, bound_error.rebind(error)), _ => { // FIXME: make this work in other cases too. @@ -1505,7 +1506,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { for pred in super::elaborate(self.tcx, std::iter::once(cond)) { let bound_predicate = pred.kind(); - if let ty::PredicateKind::Clause(ty::Clause::Trait(implication)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(implication)) = bound_predicate.skip_binder() { let error = error.to_poly_trait_ref(); @@ -1603,7 +1604,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // this can fail if the problem was higher-ranked, in which // cause I have no idea for a good error message. let bound_predicate = predicate.kind(); - let (values, err) = if let ty::PredicateKind::Clause(ty::Clause::Projection(data)) = + let (values, err) = if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) = bound_predicate.skip_binder() { let data = self.instantiate_binder_with_fresh_vars( @@ -1686,7 +1687,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}"); let secondary_span = (|| { - let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = + let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) = predicate.kind().skip_binder() else { return None; @@ -2199,7 +2200,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let bound_predicate = predicate.kind(); let mut err = match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { let trait_ref = bound_predicate.rebind(data.trait_ref); debug!(?trait_ref); @@ -2382,17 +2383,21 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { && let Some(impl_def_id) = trait_impls.non_blanket_impls().values().flatten().next() { let non_blanket_impl_count = trait_impls.non_blanket_impls().values().flatten().count(); - let message = if non_blanket_impl_count == 1 { - "use the fully-qualified path to the only available implementation".to_string() - } else { + // If there is only one implementation of the trait, suggest using it. + // Otherwise, use a placeholder comment for the implementation. + let (message, impl_suggestion) = if non_blanket_impl_count == 1 {( + "use the fully-qualified path to the only available implementation".to_string(), + format!("<{} as ", self.tcx.type_of(impl_def_id).subst_identity()) + )} else {( format!( "use a fully-qualified path to a specific available implementation ({} found)", non_blanket_impl_count - ) - }; + ), + "</* self type */ as ".to_string() + )}; let mut suggestions = vec![( path.span.shrink_to_lo(), - format!("<{} as ", self.tcx.type_of(impl_def_id).subst_identity()) + impl_suggestion )]; if let Some(generic_arg) = trait_path_segment.args { let between_span = trait_path_segment.ident.span.between(generic_arg.span_ext); @@ -2415,7 +2420,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err } - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { // Same hacky approach as above to avoid deluging user // with error messages. if arg.references_error() @@ -2453,7 +2458,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { true, ) } - ty::PredicateKind::Clause(ty::Clause::Projection(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => { if predicate.references_error() || self.tainted_by_errors().is_some() { return; } @@ -2487,7 +2492,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(data)) => { if predicate.references_error() || self.tainted_by_errors().is_some() { return; } @@ -2701,7 +2706,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>, ) { - let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = obligation.predicate.kind().skip_binder() else { return; }; + let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = obligation.predicate.kind().skip_binder() else { return; }; let (ObligationCauseCode::BindingObligation(item_def_id, span) | ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..)) = *obligation.cause.code().peel_derives() else { return; }; @@ -3325,7 +3330,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(ct)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => { let ty::ConstKind::Unevaluated(uv) = ct.kind() else { bug!("const evaluatable failed for non-unevaluated const `{ct:?}`"); }; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index fcf813e3a39..71d2380f234 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -920,7 +920,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { return false; } - if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = obligation.predicate.kind().skip_binder() + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) = obligation.predicate.kind().skip_binder() && Some(trait_pred.def_id()) == self.tcx.lang_items().sized_trait() { // Don't suggest calling to turn an unsized type into a sized type @@ -1157,7 +1157,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { self.tcx.item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| { - if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder() + if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder() && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() // args tuple will always be substs[1] && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind() @@ -1201,7 +1201,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { DefIdOrName::Name("type parameter") }; param_env.caller_bounds().iter().find_map(|pred| { - if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder() + if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) = pred.kind().skip_binder() && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() && proj.projection_ty.self_ty() == found // args tuple will always be substs[1] @@ -1639,7 +1639,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } // FIXME: account for associated `async fn`s. if let hir::Expr { span, kind: hir::ExprKind::Call(base, _), .. } = expr { - if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = obligation.predicate.kind().skip_binder() { err.span_label(*span, format!("this call returns `{}`", pred.self_ty())); @@ -2001,7 +2001,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = cause && let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx) && let Some(pred) = predicates.predicates.get(*idx) - && let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = pred.kind().skip_binder() + && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) = pred.kind().skip_binder() && self.tcx.is_fn_trait(trait_pred.def_id()) { let expected_self = @@ -2015,7 +2015,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let other_pred = predicates.into_iter() .enumerate() .find(|(other_idx, (pred, _))| match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) if self.tcx.is_fn_trait(trait_pred.def_id()) && other_idx != idx // Make sure that the self type matches @@ -2141,7 +2141,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // bound was introduced. At least one generator should be present for this diagnostic to be // modified. let (mut trait_ref, mut target_ty) = match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(p)) => (Some(p), Some(p.self_ty())), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(p)) => (Some(p), Some(p.self_ty())), _ => (None, None), }; let mut generator = None; @@ -2724,6 +2724,32 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let msg = format!("required by this bound in `{short_item_name}`"); multispan.push_span_label(span, msg); err.span_note(multispan, descr); + if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() + && let ty::ClauseKind::Trait(trait_pred) = clause + { + let def_id = trait_pred.def_id(); + let visible_item = if let Some(local) = def_id.as_local() { + // Check for local traits being reachable. + let vis = &self.tcx.resolutions(()).effective_visibilities; + // Account for non-`pub` traits in the root of the local crate. + let is_locally_reachable = self.tcx.parent(def_id).is_crate_root(); + vis.is_reachable(local) || is_locally_reachable + } else { + // Check for foreign traits being reachable. + self.tcx.visible_parent_map(()).get(&def_id).is_some() + }; + if let DefKind::Trait = tcx.def_kind(item_def_id) && !visible_item { + // FIXME(estebank): extend this to search for all the types that do + // implement this trait and list them. + err.note(format!( + "`{short_item_name}` is a \"sealed trait\", because to implement \ + it you also need to implelement `{}`, which is not accessible; \ + this is usually done to force you to use one of the provided \ + types that already implement it", + with_no_trimmed_paths!(tcx.def_path_str(def_id)), + )); + } + } } else { err.span_note(tcx.def_span(item_def_id), descr); } @@ -2816,7 +2842,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ObligationCauseCode::SizedArgumentType(ty_span) => { if let Some(span) = ty_span { if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() - && let ty::Clause::Trait(trait_pred) = clause + && let ty::ClauseKind::Trait(trait_pred) = clause && let ty::Dynamic(..) = trait_pred.self_ty().kind() { let span = if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) @@ -3597,7 +3623,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Given the predicate `fn(&T): FnOnce<(U,)>`, extract `fn(&T)` and `(U,)`, // then suggest `Option::as_deref(_mut)` if `U` can deref to `T` - if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { trait_ref, .. })) + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, .. })) = failed_pred.kind().skip_binder() && tcx.is_fn_trait(trait_ref.def_id) && let [self_ty, found_ty] = trait_ref.substs.as_slice() @@ -3826,12 +3852,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // in. For example, this would be what `Iterator::Item` is here. let ty_var = self.infcx.next_ty_var(origin); // This corresponds to `<ExprTy as Iterator>::Item = _`. - let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Projection( - ty::ProjectionPredicate { + let projection = ty::Binder::dummy(ty::PredicateKind::Clause( + ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty: self.tcx.mk_alias_ty(proj.def_id, substs), term: ty_var.into(), - }, - ))); + }), + )); let body_def_id = self.tcx.hir().enclosing_body_owner(body_id); // Add `<ExprTy as Iterator>::Item = _` obligation. ocx.register_obligation(Obligation::misc( diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 6e4bda3df03..7c5260fc67b 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -333,7 +333,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { // Evaluation will discard candidates using the leak check. // This means we need to pass it the bound version of our // predicate. - ty::PredicateKind::Clause(ty::Clause::Trait(trait_ref)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) => { let trait_obligation = obligation.with(infcx.tcx, binder.rebind(trait_ref)); self.process_trait_obligation( @@ -342,7 +342,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { &mut pending_obligation.stalled_on, ) } - ty::PredicateKind::Clause(ty::Clause::Projection(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => { let project_obligation = obligation.with(infcx.tcx, binder.rebind(data)); self.process_projection_obligation( @@ -351,15 +351,15 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { &mut pending_obligation.stalled_on, ) } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(_)) - | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_)) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::Clause(ty::Clause::WellFormed(_)) + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) | ty::PredicateKind::ObjectSafe(_) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) => { let pred = ty::Binder::dummy(infcx.instantiate_binder_with_placeholders(binder)); @@ -374,7 +374,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } }, Some(pred) => match pred { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { let trait_obligation = obligation.with(infcx.tcx, Binder::dummy(data)); self.process_trait_obligation( @@ -384,7 +384,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ) } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => { if infcx.considering_regions { infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data)); } @@ -392,7 +392,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ProcessResult::Changed(vec![]) } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( t_a, r_b, ))) => { @@ -402,7 +402,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ProcessResult::Changed(vec![]) } - ty::PredicateKind::Clause(ty::Clause::Projection(ref data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(ref data)) => { let project_obligation = obligation.with(infcx.tcx, Binder::dummy(*data)); self.process_projection_obligation( @@ -433,7 +433,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { match wf::obligations( self.selcx.infcx, obligation.param_env, @@ -498,7 +498,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(uv)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => { match const_evaluatable::is_const_evaluatable( self.selcx.infcx, uv, @@ -640,7 +640,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::AliasRelate(..) => { bug!("AliasRelate is only used for new solver") } - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq( DefineOpaqueTypes::No, ct.ty(), diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index db9cb82585f..a5481714e3e 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -65,12 +65,12 @@ pub use self::specialize::{ pub use self::structural_match::search_for_structural_match_violation; pub use self::structural_normalize::StructurallyNormalizeExt; pub use self::util::elaborate; -pub use self::util::{expand_trait_aliases, TraitAliasExpander}; -pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices}; pub use self::util::{ - supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_item, - SupertraitDefIds, + check_substs_compatible, supertrait_def_ids, supertraits, transitive_bounds, + transitive_bounds_that_define_assoc_item, SupertraitDefIds, }; +pub use self::util::{expand_trait_aliases, TraitAliasExpander}; +pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices}; pub use self::chalk_fulfill::FulfillmentContext as ChalkFulfillmentContext; @@ -357,7 +357,7 @@ pub fn normalize_param_env_or_error<'tcx>( .extract_if(|predicate| { matches!( predicate.kind().skip_binder(), - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) ) }) .collect(); diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 8c42df6e012..df93c4d45dc 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -271,7 +271,7 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Type) .flat_map(|item| tcx.explicit_item_bounds(item.def_id).subst_identity_iter_copied()) - .filter_map(|pred_span| predicate_references_self(tcx, pred_span)) + .filter_map(|(clause, span)| predicate_references_self(tcx, (clause.as_predicate(), span))) .collect() } @@ -282,11 +282,11 @@ fn predicate_references_self<'tcx>( let self_ty = tcx.types.self_param; let has_self_ty = |arg: &GenericArg<'tcx>| arg.walk().any(|arg| arg == self_ty.into()); match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(ref data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(ref data)) => { // In the case of a trait predicate, we can skip the "self" type. data.trait_ref.substs[1..].iter().any(has_self_ty).then_some(sp) } - ty::PredicateKind::Clause(ty::Clause::Projection(ref data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(ref data)) => { // And similarly for projections. This should be redundant with // the previous check because any projection should have a // matching `Trait` predicate with the same inputs, but we do @@ -304,21 +304,21 @@ fn predicate_references_self<'tcx>( // possible alternatives. data.projection_ty.substs[1..].iter().any(has_self_ty).then_some(sp) } - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(_ct, ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(_ct, ty)) => { has_self_ty(&ty.into()).then_some(sp) } ty::PredicateKind::AliasRelate(..) => bug!("`AliasRelate` not allowed as assumption"), - ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) | ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) // FIXME(generic_const_exprs): this can mention `Self` - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, @@ -353,19 +353,19 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { let predicates = tcx.predicates_of(def_id); let predicates = predicates.instantiate_identity(tcx).predicates; elaborate(tcx, predicates.into_iter()).any(|pred| match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(ref trait_pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(ref trait_pred)) => { trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0) } - ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Ambiguous @@ -592,7 +592,7 @@ fn virtual_call_violation_for_method<'tcx>( // only if the autotrait is one of the trait object's trait bounds, like // in `dyn Trait + AutoTrait`. This guarantees that trait objects only // implement auto traits if the underlying type does as well. - if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref: pred_trait_ref, constness: ty::BoundConstness::NotConst, polarity: ty::ImplPolarity::Positive, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 8399fbfc5be..2a78c5befa4 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1,5 +1,6 @@ //! Code for projecting associated types out of trait references. +use super::check_substs_compatible; use super::specialization_graph; use super::translate_substs; use super::util; @@ -1584,7 +1585,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( obligation, candidate_set, ProjectionCandidate::TraitDef, - bounds.iter(), + bounds.iter().map(|clause| clause.as_predicate()), true, ); } @@ -1607,6 +1608,10 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( let tcx = selcx.tcx(); + if !tcx.trait_def(obligation.predicate.trait_def_id(tcx)).implement_via_object { + return; + } + let self_ty = obligation.predicate.self_ty(); let object_ty = selcx.infcx.shallow_resolve(self_ty); let data = match object_ty.kind() { @@ -1649,7 +1654,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( let infcx = selcx.infcx; for predicate in env_predicates { let bound_predicate = predicate.kind(); - if let ty::PredicateKind::Clause(ty::Clause::Projection(data)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) = predicate.kind().skip_binder() { let data = bound_predicate.rebind(data); @@ -2374,47 +2379,6 @@ fn confirm_impl_candidate<'cx, 'tcx>( } } -// Verify that the trait item and its implementation have compatible substs lists -fn check_substs_compatible<'tcx>( - tcx: TyCtxt<'tcx>, - assoc_item: ty::AssocItem, - substs: ty::SubstsRef<'tcx>, -) -> bool { - fn check_substs_compatible_inner<'tcx>( - tcx: TyCtxt<'tcx>, - generics: &'tcx ty::Generics, - args: &'tcx [ty::GenericArg<'tcx>], - ) -> bool { - if generics.count() != args.len() { - return false; - } - - let (parent_args, own_args) = args.split_at(generics.parent_count); - - if let Some(parent) = generics.parent - && let parent_generics = tcx.generics_of(parent) - && !check_substs_compatible_inner(tcx, parent_generics, parent_args) { - return false; - } - - for (param, arg) in std::iter::zip(&generics.params, own_args) { - match (¶m.kind, arg.unpack()) { - (ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_)) - | (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_)) - | (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {} - _ => return false, - } - } - - true - } - - let generics = tcx.generics_of(assoc_item.def_id); - // Chop off any additional substs (RPITIT) substs - let substs = &substs[0..generics.count().min(substs.len())]; - check_substs_compatible_inner(tcx, generics, substs) -} - fn confirm_impl_trait_in_trait_candidate<'tcx>( selcx: &mut SelectionContext<'_, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index f8ceee50054..c93c30b7053 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -67,7 +67,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { let mut _orig_values = OriginalQueryValues::default(); let param_env = match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { // we ignore the value set to it. let mut _constness = pred.constness; obligation diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 2d97a808225..1b6e92946c4 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -322,8 +322,12 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> }; // `tcx.normalize_projection_ty` may normalize to a type that still has // unevaluated consts, so keep normalizing here if that's the case. - if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) { - res.try_super_fold_with(self)? + // Similarly, `tcx.normalize_weak_ty` will only unwrap one layer of type + // and we need to continue folding it to reveal the TAIT behind it. + if res != ty + && (res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) || kind == ty::Weak) + { + res.try_fold_with(self)? } else { res } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs index 7405ca31cde..44671a07659 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs @@ -68,7 +68,7 @@ fn relate_mir_and_user_ty<'tcx>( // FIXME(#104764): We should check well-formedness before normalization. let predicate = - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(user_ty.into()))); + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(user_ty.into()))); ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate)); Ok(()) } @@ -120,7 +120,7 @@ fn relate_mir_and_user_substs<'tcx>( let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty); ocx.eq(&cause, param_env, self_ty, impl_self_ty)?; - let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed( + let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( impl_self_ty.into(), ))); ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate)); @@ -137,7 +137,8 @@ fn relate_mir_and_user_substs<'tcx>( // them? This would only be relevant if some input // type were ill-formed but did not appear in `ty`, // which...could happen with normalization... - let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(ty.into()))); + let predicate = + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty.into()))); ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate)); Ok(()) } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index 8761f4fea6c..7d0dc740cf5 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -108,7 +108,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( // learn anything new from those. if obligation.predicate.has_non_region_infer() { match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(..)) + ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) | ty::PredicateKind::AliasRelate(..) => { ocx.register_obligation(obligation.clone()); } @@ -121,33 +121,33 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( Some(pred) => pred, }; match pred { - ty::PredicateKind::Clause(ty::Clause::Trait(..)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound // if we ever support that - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::Projection(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => {} // We need to search through *all* WellFormed predicates - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { wf_args.push(arg); } // We need to register region relationships - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( r_a, r_b, ))) => outlives_bounds.push(ty::OutlivesPredicate(r_a.into(), r_b)), - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( ty_a, r_b, ))) => outlives_bounds.push(ty::OutlivesPredicate(ty_a.into(), r_b)), diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs index 47850bc330d..789ef647246 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs @@ -18,7 +18,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { // `&T`, accounts for about 60% percentage of the predicates // we have to prove. No need to canonicalize and all that for // such cases. - if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_ref)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) = key.value.predicate.kind().skip_binder() { if let Some(sized_def_id) = tcx.lang_items().sized_trait() { diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index f2dfa6921f4..8eef7d5d63f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -402,7 +402,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; for &(predicate, _) in self.tcx().predicates_of(impl_def_id).predicates { - let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) + let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = predicate.kind().skip_binder() else { continue }; if fn_ptr_trait != pred.trait_ref.def_id { continue; @@ -417,17 +417,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Fast path to avoid evaluating an obligation that trivially holds. // There may be more bounds, but these are checked by the regular path. ty::FnPtr(..) => return false, + // These may potentially implement `FnPtr` ty::Placeholder(..) | ty::Dynamic(_, _, _) | ty::Alias(_, _) | ty::Infer(_) - | ty::Param(..) => {} + | ty::Param(..) + | ty::Bound(_, _) => {} - ty::Bound(_, _) => span_bug!( - obligation.cause.span(), - "cannot have escaping bound var in self type of {obligation:#?}" - ), // These can't possibly implement `FnPtr` as they are concrete types // and not `FnPtr` ty::Bool @@ -463,7 +461,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.tcx().mk_predicate(obligation.predicate.map_bound(|mut pred| { pred.trait_ref = ty::TraitRef::new(self.tcx(), fn_ptr_trait, [pred.trait_ref.self_ty()]); - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) })), ); if let Ok(r) = self.infcx.evaluate_obligation(&obligation) { @@ -554,6 +552,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { "assemble_candidates_from_object_ty", ); + if !self.tcx().trait_def(obligation.predicate.def_id()).implement_via_object { + return; + } + self.infcx.probe(|_snapshot| { if obligation.has_non_region_late_bound() { return; diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 3c356978d5c..a50af417a44 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -170,7 +170,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let candidate_predicate = tcx.item_bounds(def_id).map_bound(|i| i[idx]).subst(tcx, substs); let candidate = candidate_predicate - .to_opt_poly_trait_pred() + .as_trait_clause() .expect("projection candidate is not a trait predicate") .map_bound(|t| t.trait_ref); let mut obligations = Vec::new(); @@ -631,7 +631,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let assoc_ty_substs = tcx.mk_substs(&substs); let bound = bound.map_bound(|b| b.kind().skip_binder()).subst(tcx, assoc_ty_substs); - tcx.mk_predicate(ty::Binder::bind_with_vars(bound, bound_vars)) + ty::Binder::bind_with_vars(bound, bound_vars).to_predicate(tcx) }; let normalized_bound = normalize_with_depth_to( self, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index ca2ae9b5235..0a8b7b688e7 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -643,7 +643,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ensure_sufficient_stack(|| { let bound_predicate = obligation.predicate.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(t)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => { let t = bound_predicate.rebind(t); debug_assert!(!t.has_escaping_bound_vars()); let obligation = obligation.with(self.tcx(), t); @@ -674,7 +674,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { // So, there is a bit going on here. First, `WellFormed` predicates // are coinductive, like trait predicates with auto traits. // This means that we need to detect if we have recursively @@ -760,7 +760,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(pred)) => { // A global type with no free lifetimes or generic parameters // outlives anything. if pred.0.has_free_regions() @@ -774,7 +774,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) => { // We do not consider region relationships when evaluating trait matches. Ok(EvaluatedToOkModuloRegions) } @@ -787,7 +787,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::PredicateKind::Clause(ty::Clause::Projection(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => { let data = bound_predicate.rebind(data); let project_obligation = obligation.with(self.tcx(), data); match project::poly_project_and_unify_type(self, &project_obligation) { @@ -862,7 +862,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(uv)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => { match const_evaluatable::is_const_evaluatable( self.infcx, uv, @@ -974,7 +974,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { bug!("AliasRelate is only used for new solver") } ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig), - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { match self.infcx.at(&obligation.cause, obligation.param_env).eq( DefineOpaqueTypes::No, ct.ty(), @@ -1668,9 +1668,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .enumerate() .filter_map(|(idx, bound)| { let bound_predicate = bound.kind(); - if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = - bound_predicate.skip_binder() - { + if let ty::ClauseKind::Trait(pred) = bound_predicate.skip_binder() { let bound = bound_predicate.rebind(pred.trait_ref); if self.infcx.probe(|_| { match self.match_normalize_trait_ref( diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 9a4b72013b8..68ba8ceaa43 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -521,7 +521,8 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti }); p = tcx.mk_predicate( - new_trait_pred.map_bound(|p| ty::PredicateKind::Clause(ty::Clause::Trait(p))), + new_trait_pred + .map_bound(|p| ty::PredicateKind::Clause(ty::ClauseKind::Trait(p))), ) } } diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 906c357e8ca..05a7f3e3b02 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -302,3 +302,44 @@ pub enum TupleArgumentsFlag { Yes, No, } + +// Verify that the trait item and its implementation have compatible substs lists +pub fn check_substs_compatible<'tcx>( + tcx: TyCtxt<'tcx>, + assoc_item: ty::AssocItem, + substs: ty::SubstsRef<'tcx>, +) -> bool { + fn check_substs_compatible_inner<'tcx>( + tcx: TyCtxt<'tcx>, + generics: &'tcx ty::Generics, + args: &'tcx [ty::GenericArg<'tcx>], + ) -> bool { + if generics.count() != args.len() { + return false; + } + + let (parent_args, own_args) = args.split_at(generics.parent_count); + + if let Some(parent) = generics.parent + && let parent_generics = tcx.generics_of(parent) + && !check_substs_compatible_inner(tcx, parent_generics, parent_args) { + return false; + } + + for (param, arg) in std::iter::zip(&generics.params, own_args) { + match (¶m.kind, arg.unpack()) { + (ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_)) + | (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_)) + | (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {} + _ => return false, + } + } + + true + } + + let generics = tcx.generics_of(assoc_item.def_id); + // Chop off any additional substs (RPITIT) substs + let substs = &substs[0..generics.count().min(substs.len())]; + check_substs_compatible_inner(tcx, generics, substs) +} diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 676978fabe4..e96e89ce73c 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -77,12 +77,19 @@ pub fn unnormalized_obligations<'tcx>( param_env: ty::ParamEnv<'tcx>, arg: GenericArg<'tcx>, ) -> Option<Vec<traits::PredicateObligation<'tcx>>> { + debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg)); + + // However, if `arg` IS an unresolved inference variable, returns `None`, + // because we are not able to make any progress at all. This is to prevent + // "livelock" where we say "$0 is WF if $0 is WF". + if arg.is_non_region_infer() { + return None; + } + if let ty::GenericArgKind::Lifetime(..) = arg.unpack() { return Some(vec![]); } - debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg)); - let mut wf = WfPredicates { infcx, param_env, @@ -142,29 +149,32 @@ pub fn predicate_obligations<'tcx>( // It's ok to skip the binder here because wf code is prepared for it match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(t)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => { wf.compute_trait_pred(&t, Elaborate::None); } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) => {} - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(ty, _reg))) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) => {} + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( + ty, + _reg, + ))) => { wf.compute(ty.into()); } - ty::PredicateKind::Clause(ty::Clause::Projection(t)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(t)) => { wf.compute_projection(t.projection_ty); wf.compute(match t.term.unpack() { ty::TermKind::Ty(ty) => ty.into(), ty::TermKind::Const(c) => c.into(), }) } - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { wf.compute(ct.into()); wf.compute(ty.into()); } - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { wf.compute(arg); } - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(ct)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => { wf.compute(ct.into()); } @@ -247,7 +257,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( // It is fine to skip the binder as we don't care about regions here. match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) => { // The obligation comes not from the current `impl` nor the `trait` being implemented, // but rather from a "second order" obligation, where an associated type has a // projection coming from another associated type. See @@ -264,7 +274,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( cause.span = impl_item_span; } } - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { // An associated item obligation born out of the `trait` failed to be met. An example // can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`. debug!("extended_cause_with_original_assoc_item_obligation trait proj {:?}", pred); @@ -386,7 +396,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause, depth, param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(arg))), + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( + arg, + ))), ) }), ); @@ -478,7 +490,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause.clone(), depth, param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(arg))), + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( + arg, + ))), ) }), ); @@ -522,7 +536,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.out.extend(obligations); let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( - ty::Clause::ConstEvaluatable(ct), + ty::ClauseKind::ConstEvaluatable(ct), )); let cause = self.cause(traits::WellFormed(None)); self.out.push(traits::Obligation::with_depth( @@ -543,7 +557,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.recursion_depth, self.param_env, ty::Binder::dummy(ty::PredicateKind::Clause( - ty::Clause::WellFormed(ct.into()), + ty::ClauseKind::WellFormed(ct.into()), )), )); } @@ -556,7 +570,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // we would not be proving bounds we should. let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( - ty::Clause::ConstEvaluatable(ct), + ty::ClauseKind::ConstEvaluatable(ct), )); let cause = self.cause(traits::WellFormed(None)); self.out.push(traits::Obligation::with_depth( @@ -658,9 +672,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause, depth, param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::TypeOutlives( - ty::OutlivesPredicate(rty, r), - ))), + ty::Binder::dummy(ty::PredicateKind::Clause( + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(rty, r)), + )), )); } } @@ -788,7 +802,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause, self.recursion_depth, param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed( + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( ty.into(), ))), )); @@ -970,21 +984,21 @@ pub(crate) fn required_region_bounds<'tcx>( .filter_map(|pred| { debug!(?pred); match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::Clause(ty::Clause::Trait(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( ref t, ref r, ))) => { diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 38f94c38861..7e64cbdf54a 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -54,7 +54,9 @@ impl<'tcx> RustIrDatabase<'tcx> { .tcx .explicit_item_bounds(def_id) .subst_iter_copied(self.interner.tcx, &bound_vars) - .filter_map(|(bound, _)| LowerInto::<Option<_>>::lower_into(bound, self.interner)) + .filter_map(|(bound, _)| { + LowerInto::<Option<_>>::lower_into(bound.as_predicate(), self.interner) + }) .collect() } } @@ -520,7 +522,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t .filter_map(|bound| { LowerInto::< Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>> - >::lower_into(bound, self.interner) + >::lower_into(bound.as_predicate(), self.interner) }) .collect(); diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 1d4219bc0c0..aefe57e0ddf 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -96,12 +96,12 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<' ty::PredicateKind::TypeWellFormedFromEnv(ty) => { chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner))) } - ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Trait( predicate.trait_ref.lower_into(interner), )) } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => { chalk_ir::DomainGoal::Holds(chalk_ir::WhereClause::LifetimeOutlives( chalk_ir::LifetimeOutlives { a: predicate.0.lower_into(interner), @@ -109,7 +109,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<' }, )) } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => { chalk_ir::DomainGoal::Holds(chalk_ir::WhereClause::TypeOutlives( chalk_ir::TypeOutlives { ty: predicate.0.lower_into(interner), @@ -117,12 +117,12 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<' }, )) } - ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => { chalk_ir::DomainGoal::Holds(chalk_ir::WhereClause::AliasEq( predicate.lower_into(interner), )) } - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => match arg.unpack() { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => match arg.unpack() { ty::GenericArgKind::Type(ty) => chalk_ir::DomainGoal::WellFormed( chalk_ir::WellFormed::Ty(ty.lower_into(interner)), ), @@ -132,12 +132,12 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<' )), }, ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::Ambiguous | ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", predicate), }; @@ -166,12 +166,12 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi collect_bound_vars(interner, interner.tcx, self.kind()); let value = match predicate { - ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner)), )) } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => { chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { a: predicate.0.lower_into(interner), @@ -179,7 +179,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi }), )) } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => { chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { ty: predicate.0.lower_into(interner), @@ -187,12 +187,12 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi }), )) } - ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => { chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)), )) } - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => match arg.unpack() { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => match arg.unpack() { GenericArgKind::Type(ty) => match ty.kind() { // FIXME(chalk): In Chalk, a placeholder is WellFormed if it // `FromEnv`. However, when we "lower" Params, we don't update @@ -228,10 +228,10 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi // We can defer this, but ultimately we'll want to express // some of these in terms of chalk operations. ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::Ambiguous | ty::PredicateKind::ConstEquate(..) => { chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) @@ -654,33 +654,33 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<' let (predicate, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, self.kind()); let value = match predicate { - ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { Some(chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner))) } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => { Some(chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { a: predicate.0.lower_into(interner), b: predicate.1.lower_into(interner), })) } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => { Some(chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { ty: predicate.0.lower_into(interner), lifetime: predicate.1.lower_into(interner), })) } - ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => { Some(chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner))) } - ty::PredicateKind::Clause(ty::Clause::WellFormed(_ty)) => None, - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None, + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_ty)) => None, + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => None, ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => { @@ -792,7 +792,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru let (predicate, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, self.kind()); match predicate { - ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { Some(chalk_ir::Binders::new( binders, chalk_solve::rust_ir::InlineBound::TraitBound( @@ -800,23 +800,23 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru ), )) } - ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => { Some(chalk_ir::Binders::new( binders, chalk_solve::rust_ir::InlineBound::AliasEqBound(predicate.lower_into(interner)), )) } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_predicate)) => None, - ty::PredicateKind::Clause(ty::Clause::WellFormed(_ty)) => None, - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None, + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(_predicate)) => None, + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_ty)) => None, + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => None, - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => { diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index 73756caf372..e8917d72483 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -1,6 +1,5 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; -use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use rustc_span::source_map::DUMMY_SP; use rustc_trait_selection::traits::query::CanonicalPredicateGoal; @@ -18,12 +17,8 @@ fn evaluate_obligation<'tcx>( ) -> Result<EvaluationResult, OverflowError> { assert!(!tcx.next_trait_solver_globally()); debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal); - // HACK This bubble is required for this tests to pass: - // impl-trait/issue99642.rs - let (ref infcx, goal, _canonical_inference_vars) = tcx - .infer_ctxt() - .with_opaque_type_inference(DefiningAnchor::Bubble) - .build_with_canonical(DUMMY_SP, &canonical_goal); + let (ref infcx, goal, _canonical_inference_vars) = + tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal); debug!("evaluate_obligation: goal={:#?}", goal); let ParamEnvAnd { param_env, value: predicate } = goal; diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 7f6d53fe860..96896526a12 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -56,18 +56,18 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<TyCtxt<'tcx>> + Par fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool { match p.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) => false, - ty::PredicateKind::Clause(ty::Clause::Trait(..)) - | ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) => false, + ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => true, diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index 9904acb1c0d..98d814d54f2 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -2,7 +2,6 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::{FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{ParamEnvAnd, Predicate}; use rustc_trait_selection::infer::InferCtxtBuilderExt; @@ -106,15 +105,10 @@ fn type_op_prove_predicate<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, ProvePredicate<'tcx>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> { - // HACK This bubble is required for this test to pass: - // impl-trait/issue-99642.rs - tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter_canonical_trait_query( - &canonicalized, - |ocx, key| { - type_op_prove_predicate_with_cause(ocx, key, ObligationCause::dummy()); - Ok(()) - }, - ) + tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| { + type_op_prove_predicate_with_cause(ocx, key, ObligationCause::dummy()); + Ok(()) + }) } /// The core of the `type_op_prove_predicate` query: for diagnostics purposes in NLL HRTB errors, diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 658ab03c0f4..5b731641e9d 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -259,7 +259,7 @@ fn associated_type_for_impl_trait_in_trait( opaque_ty_def_id: LocalDefId, ) -> LocalDefId { let (hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id)) = - tcx.hir().expect_item(opaque_ty_def_id).expect_opaque_ty().origin + tcx.opaque_type_origin(opaque_ty_def_id) else { bug!("expected opaque for {opaque_ty_def_id:?}"); }; diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index ce77df0df5d..387adda8f57 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -78,8 +78,9 @@ pub(crate) fn destructure_const<'tcx>( fn check_binop(op: mir::BinOp) -> bool { use mir::BinOp::*; match op { - Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Shl | Shr | Eq | Lt | Le | Ne - | Ge | Gt => true, + Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor + | BitAnd | BitOr | Shl | ShlUnchecked | Shr | ShrUnchecked | Eq | Lt | Le | Ne | Ge + | Gt => true, Offset => false, } } diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs index 553bf40ef3a..947d4bbe86e 100644 --- a/compiler/rustc_ty_utils/src/errors.rs +++ b/compiler/rustc_ty_utils/src/errors.rs @@ -113,7 +113,7 @@ pub struct DuplicateArg<'tcx> { } #[derive(Diagnostic)] -#[diag(ty_utils_impl_trait_not_param)] +#[diag(ty_utils_impl_trait_not_param, code = "E0792")] pub struct NotParam<'tcx> { pub arg: GenericArg<'tcx>, #[primary_span] diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 7015778e24b..c8c2c8286b0 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -145,17 +145,35 @@ fn layout_of_uncached<'tcx>( return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr))); } - let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env); - let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() // Projection eagerly bails out when the pointee references errors, // fall back to structurally deducing metadata. && !pointee.references_error() { - let metadata_ty = tcx.normalize_erasing_regions( + let pointee_metadata = tcx.mk_projection(metadata_def_id, [pointee]); + let metadata_ty = match tcx.try_normalize_erasing_regions( param_env, - tcx.mk_projection(metadata_def_id, [pointee]), - ); + pointee_metadata, + ) { + Ok(metadata_ty) => metadata_ty, + Err(mut err) => { + // Usually `<Ty as Pointee>::Metadata` can't be normalized because + // its struct tail cannot be normalized either, so try to get a + // more descriptive layout error here, which will lead to less confusing + // diagnostics. + match tcx.try_normalize_erasing_regions( + param_env, + tcx.struct_tail_without_normalization(pointee), + ) { + Ok(_) => {}, + Err(better_err) => { + err = better_err; + } + } + return Err(LayoutError::NormalizationFailure(pointee, err)); + }, + }; + let metadata_layout = cx.layout_of(metadata_ty)?; // If the metadata is a 1-zst, then the pointer is thin. if metadata_layout.is_zst() && metadata_layout.align.abi.bytes() == 1 { @@ -163,10 +181,13 @@ fn layout_of_uncached<'tcx>( } let Abi::Scalar(metadata) = metadata_layout.abi else { - return Err(LayoutError::Unknown(unsized_part)); + return Err(LayoutError::Unknown(pointee)); }; + metadata } else { + let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env); + match unsized_part.kind() { ty::Foreign(..) => { return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr))); @@ -178,7 +199,7 @@ fn layout_of_uncached<'tcx>( vtable } _ => { - return Err(LayoutError::Unknown(unsized_part)); + return Err(LayoutError::Unknown(pointee)); } } }; @@ -944,7 +965,7 @@ fn variant_info_for_generator<'tcx>( return (vec![], None); }; - let (generator, state_specific_names) = cx.tcx.generator_layout_and_saved_local_names(def_id); + let generator = cx.tcx.optimized_mir(def_id).generator_layout().unwrap(); let upvar_names = cx.tcx.closure_saved_names_of_captured_variables(def_id); let mut upvars_size = Size::ZERO; @@ -959,7 +980,7 @@ fn variant_info_for_generator<'tcx>( upvars_size = upvars_size.max(offset + field_layout.size); FieldInfo { kind: FieldKind::Upvar, - name: Symbol::intern(&name), + name: *name, offset: offset.bytes(), size: field_layout.size.bytes(), align: field_layout.align.abi.bytes(), @@ -983,9 +1004,10 @@ fn variant_info_for_generator<'tcx>( variant_size = variant_size.max(offset + field_layout.size); FieldInfo { kind: FieldKind::GeneratorLocal, - name: state_specific_names.get(*local).copied().flatten().unwrap_or( - Symbol::intern(&format!(".generator_field{}", local.as_usize())), - ), + name: generator.field_names[*local].unwrap_or(Symbol::intern(&format!( + ".generator_field{}", + local.as_usize() + ))), offset: offset.bytes(), size: field_layout.size.bytes(), align: field_layout.align.abi.bytes(), diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 4e91dd380e8..29de8bf0e53 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -1,12 +1,11 @@ use rustc_data_structures::fx::FxHashSet; -use rustc_errors::ErrorGuaranteed; use rustc_hir::{def::DefKind, def_id::LocalDefId}; use rustc_middle::query::Providers; use rustc_middle::ty::util::{CheckRegions, NotUniqueParam}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_span::Span; -use rustc_type_ir::AliasKind; +use rustc_trait_selection::traits::check_substs_compatible; use std::ops::ControlFlow; use crate::errors::{DuplicateArg, NotParam}; @@ -19,21 +18,35 @@ struct OpaqueTypeCollector<'tcx> { /// Avoid infinite recursion due to recursive declarations. seen: FxHashSet<LocalDefId>, + + span: Option<Span>, } impl<'tcx> OpaqueTypeCollector<'tcx> { - fn collect( - tcx: TyCtxt<'tcx>, - item: LocalDefId, - val: ty::Binder<'tcx, impl TypeVisitable<TyCtxt<'tcx>>>, - ) -> Vec<LocalDefId> { - let mut collector = Self { tcx, opaques: Vec::new(), item, seen: Default::default() }; - val.skip_binder().visit_with(&mut collector); - collector.opaques + fn new(tcx: TyCtxt<'tcx>, item: LocalDefId) -> Self { + Self { tcx, opaques: Vec::new(), item, seen: Default::default(), span: None } } fn span(&self) -> Span { - self.tcx.def_span(self.item) + self.span.unwrap_or_else(|| { + self.tcx.def_ident_span(self.item).unwrap_or_else(|| self.tcx.def_span(self.item)) + }) + } + + fn visit_spanned(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) { + let old = self.span; + self.span = Some(span); + value.visit_with(self); + self.span = old; + } + + fn parent_trait_ref(&self) -> Option<ty::TraitRef<'tcx>> { + let parent = self.parent()?; + if matches!(self.tcx.def_kind(parent), DefKind::Impl { .. }) { + Some(self.tcx.impl_trait_ref(parent)?.subst_identity()) + } else { + None + } } fn parent(&self) -> Option<LocalDefId> { @@ -51,91 +64,124 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { } impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> { - type BreakTy = ErrorGuaranteed; - #[instrument(skip(self), ret, level = "trace")] - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<ErrorGuaranteed> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> { + t.super_visit_with(self)?; match t.kind() { - ty::Alias(AliasKind::Opaque, alias_ty) if alias_ty.def_id.is_local() => { + ty::Alias(ty::Opaque, alias_ty) if alias_ty.def_id.is_local() => { if !self.seen.insert(alias_ty.def_id.expect_local()) { return ControlFlow::Continue(()); } + + self.opaques.push(alias_ty.def_id.expect_local()); + match self.tcx.uses_unique_generic_params(alias_ty.substs, CheckRegions::Bound) { Ok(()) => { // FIXME: implement higher kinded lifetime bounds on nested opaque types. They are not // supported at all, so this is sound to do, but once we want to support them, you'll // start seeing the error below. - self.opaques.push(alias_ty.def_id.expect_local()); - // Collect opaque types nested within the associated type bounds of this opaque type. - for (pred, _span) in self + // We use identity substs here, because we already know that the opaque type uses + // only generic parameters, and thus substituting would not give us more information. + for (pred, span) in self .tcx .explicit_item_bounds(alias_ty.def_id) - .subst_iter_copied(self.tcx, alias_ty.substs) + .subst_identity_iter_copied() { trace!(?pred); - pred.visit_with(self)?; + self.visit_spanned(span, pred); } - - ControlFlow::Continue(()) } Err(NotUniqueParam::NotParam(arg)) => { - let err = self.tcx.sess.emit_err(NotParam { + self.tcx.sess.emit_err(NotParam { arg, span: self.span(), opaque_span: self.tcx.def_span(alias_ty.def_id), }); - ControlFlow::Break(err) } Err(NotUniqueParam::DuplicateParam(arg)) => { - let err = self.tcx.sess.emit_err(DuplicateArg { + self.tcx.sess.emit_err(DuplicateArg { arg, span: self.span(), opaque_span: self.tcx.def_span(alias_ty.def_id), }); - ControlFlow::Break(err) } } } - ty::Alias(AliasKind::Projection, alias_ty) => { - if let Some(parent) = self.parent() { - trace!(?alias_ty); - let (trait_ref, own_substs) = alias_ty.trait_ref_and_own_substs(self.tcx); - - trace!(?trait_ref, ?own_substs); - // This avoids having to do normalization of `Self::AssocTy` by only - // supporting the case of a method defining opaque types from assoc types - // in the same impl block. - if trait_ref.self_ty() == self.tcx.type_of(parent).subst_identity() { - for assoc in self.tcx.associated_items(parent).in_definition_order() { + ty::Alias(ty::Weak, alias_ty) if alias_ty.def_id.is_local() => { + self.tcx + .type_of(alias_ty.def_id) + .subst(self.tcx, alias_ty.substs) + .visit_with(self)?; + } + ty::Alias(ty::Projection, alias_ty) => { + // This avoids having to do normalization of `Self::AssocTy` by only + // supporting the case of a method defining opaque types from assoc types + // in the same impl block. + if let Some(parent_trait_ref) = self.parent_trait_ref() { + // If the trait ref of the associated item and the impl differs, + // then we can't use the impl's identity substitutions below, so + // just skip. + if alias_ty.trait_ref(self.tcx) == parent_trait_ref { + let parent = self.parent().expect("we should have a parent here"); + + for &assoc in self.tcx.associated_items(parent).in_definition_order() { trace!(?assoc); - if assoc.trait_item_def_id == Some(alias_ty.def_id) { - // We reconstruct the generic args of the associated type within the impl - // from the impl's generics and the generic args passed to the type via the - // projection. - let substs = ty::InternalSubsts::identity_for_item( - self.tcx, - parent.to_def_id(), - ); - trace!(?substs); - let substs: Vec<_> = - substs.iter().chain(own_substs.iter().copied()).collect(); - trace!(?substs); - // Find opaque types in this associated type. + if assoc.trait_item_def_id != Some(alias_ty.def_id) { + continue; + } + + // If the type is further specializable, then the type_of + // is not actually correct below. + if !assoc.defaultness(self.tcx).is_final() { + continue; + } + + let impl_substs = alias_ty.substs.rebase_onto( + self.tcx, + parent_trait_ref.def_id, + ty::InternalSubsts::identity_for_item(self.tcx, parent), + ); + + if check_substs_compatible(self.tcx, assoc, impl_substs) { return self .tcx .type_of(assoc.def_id) - .subst(self.tcx, &substs) + .subst(self.tcx, impl_substs) .visit_with(self); + } else { + self.tcx.sess.delay_span_bug( + self.tcx.def_span(assoc.def_id), + "item had incorrect substs", + ); } } } } - t.super_visit_with(self) } - _ => t.super_visit_with(self), + ty::Adt(def, _) if def.did().is_local() => { + if !self.seen.insert(def.did().expect_local()) { + return ControlFlow::Continue(()); + } + for variant in def.variants().iter() { + for field in variant.fields.iter() { + // Don't use the `ty::Adt` substs, we either + // * found the opaque in the substs + // * will find the opaque in the unsubstituted fields + // The only other situation that can occur is that after substituting, + // some projection resolves to an opaque that we would have otherwise + // not found. While we could substitute and walk those, that would mean we + // would have to walk all substitutions of an Adt, which can quickly + // degenerate into looking at an exponential number of types. + let ty = self.tcx.type_of(field.did).subst_identity(); + self.visit_spanned(self.tcx.def_span(field.did), ty); + } + } + } + _ => trace!(kind=?t.kind()), } + ControlFlow::Continue(()) } } @@ -146,21 +192,29 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [ match kind { // We're also doing this for `AssocTy` for the wf checks in `check_opaque_meets_bounds` DefKind::Fn | DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { - let defined_opaques = match kind { - DefKind::Fn => { - OpaqueTypeCollector::collect(tcx, item, tcx.fn_sig(item).subst_identity()) + let mut collector = OpaqueTypeCollector::new(tcx, item); + match kind { + // Walk over the signature of the function-like to find the opaques. + DefKind::AssocFn | DefKind::Fn => { + let ty_sig = tcx.fn_sig(item).subst_identity(); + let hir_sig = tcx.hir().get_by_def_id(item).fn_sig().unwrap(); + // Walk over the inputs and outputs manually in order to get good spans for them. + collector.visit_spanned(hir_sig.decl.output.span(), ty_sig.output()); + for (hir, ty) in hir_sig.decl.inputs.iter().zip(ty_sig.inputs().iter()) { + collector.visit_spanned(hir.span, ty.map_bound(|x| *x)); + } } - DefKind::AssocFn => { - OpaqueTypeCollector::collect(tcx, item, tcx.fn_sig(item).subst_identity()) + // Walk over the type of the item to find opaques. + DefKind::AssocTy | DefKind::AssocConst => { + let span = match tcx.hir().get_by_def_id(item).ty() { + Some(ty) => ty.span, + _ => tcx.def_span(item), + }; + collector.visit_spanned(span, tcx.type_of(item).subst_identity()); } - DefKind::AssocTy | DefKind::AssocConst => OpaqueTypeCollector::collect( - tcx, - item, - ty::Binder::dummy(tcx.type_of(item).subst_identity()), - ), _ => unreachable!(), - }; - tcx.arena.alloc_from_iter(defined_opaques) + } + tcx.arena.alloc_from_iter(collector.opaques) } DefKind::Mod | DefKind::Struct @@ -189,7 +243,9 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [ | DefKind::GlobalAsm | DefKind::Impl { .. } | DefKind::Closure - | DefKind::Generator => &[], + | DefKind::Generator => { + span_bug!(tcx.def_span(item), "{kind:?} is type checked as part of its parent") + } } } diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 34d3acae546..b3305b8ca6d 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -258,12 +258,12 @@ use core::iter; use core::marker::{PhantomData, Unsize}; #[cfg(not(no_global_oom_handling))] use core::mem::size_of_val; -use core::mem::{self, align_of_val_raw, forget}; -use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver}; +use core::mem::{self, align_of_val_raw, forget, ManuallyDrop}; +use core::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Receiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; #[cfg(not(no_global_oom_handling))] use core::pin::Pin; -use core::ptr::{self, NonNull}; +use core::ptr::{self, drop_in_place, NonNull}; #[cfg(not(no_global_oom_handling))] use core::slice::from_raw_parts_mut; @@ -1169,7 +1169,7 @@ impl<T: ?Sized> Rc<T> { #[inline] #[stable(feature = "ptr_eq", since = "1.17.0")] /// Returns `true` if the two `Rc`s point to the same allocation in a vein similar to - /// [`ptr::eq`]. See [that function][`ptr::eq`] for caveats when comparing `dyn Trait` pointers. + /// [`ptr::eq`]. This function ignores the metadata of `dyn Trait` pointers. /// /// # Examples /// @@ -1184,7 +1184,7 @@ impl<T: ?Sized> Rc<T> { /// assert!(!Rc::ptr_eq(&five, &other_five)); /// ``` pub fn ptr_eq(this: &Self, other: &Self) -> bool { - this.ptr.as_ptr() == other.ptr.as_ptr() + this.ptr.as_ptr() as *const () == other.ptr.as_ptr() as *const () } } @@ -2466,8 +2466,8 @@ impl<T: ?Sized> Weak<T> { } /// Returns `true` if the two `Weak`s point to the same allocation similar to [`ptr::eq`], or if - /// both don't point to any allocation (because they were created with `Weak::new()`). See [that - /// function][`ptr::eq`] for caveats when comparing `dyn Trait` pointers. + /// both don't point to any allocation (because they were created with `Weak::new()`). However, + /// this function ignores the metadata of `dyn Trait` pointers. /// /// # Notes /// @@ -2508,7 +2508,7 @@ impl<T: ?Sized> Weak<T> { #[must_use] #[stable(feature = "weak_ptr_eq", since = "1.39.0")] pub fn ptr_eq(&self, other: &Self) -> bool { - self.ptr.as_ptr() == other.ptr.as_ptr() + ptr::eq(self.ptr.as_ptr() as *const (), other.ptr.as_ptr() as *const ()) } } @@ -2744,3 +2744,139 @@ fn data_offset_align(align: usize) -> usize { let layout = Layout::new::<RcBox<()>>(); layout.size() + layout.padding_needed_for(align) } + +/// A uniquely owned `Rc` +/// +/// This represents an `Rc` that is known to be uniquely owned -- that is, have exactly one strong +/// reference. Multiple weak pointers can be created, but attempts to upgrade those to strong +/// references will fail unless the `UniqueRc` they point to has been converted into a regular `Rc`. +/// +/// Because they are uniquely owned, the contents of a `UniqueRc` can be freely mutated. A common +/// use case is to have an object be mutable during its initialization phase but then have it become +/// immutable and converted to a normal `Rc`. +/// +/// This can be used as a flexible way to create cyclic data structures, as in the example below. +/// +/// ``` +/// #![feature(unique_rc_arc)] +/// use std::rc::{Rc, Weak, UniqueRc}; +/// +/// struct Gadget { +/// #[allow(dead_code)] +/// me: Weak<Gadget>, +/// } +/// +/// fn create_gadget() -> Option<Rc<Gadget>> { +/// let mut rc = UniqueRc::new(Gadget { +/// me: Weak::new(), +/// }); +/// rc.me = UniqueRc::downgrade(&rc); +/// Some(UniqueRc::into_rc(rc)) +/// } +/// +/// create_gadget().unwrap(); +/// ``` +/// +/// An advantage of using `UniqueRc` over [`Rc::new_cyclic`] to build cyclic data structures is that +/// [`Rc::new_cyclic`]'s `data_fn` parameter cannot be async or return a [`Result`]. As shown in the +/// previous example, `UniqueRc` allows for more flexibility in the construction of cyclic data, +/// including fallible or async constructors. +#[unstable(feature = "unique_rc_arc", issue = "112566")] +#[derive(Debug)] +pub struct UniqueRc<T> { + ptr: NonNull<RcBox<T>>, + phantom: PhantomData<RcBox<T>>, +} + +impl<T> UniqueRc<T> { + /// Creates a new `UniqueRc` + /// + /// Weak references to this `UniqueRc` can be created with [`UniqueRc::downgrade`]. Upgrading + /// these weak references will fail before the `UniqueRc` has been converted into an [`Rc`]. + /// After converting the `UniqueRc` into an [`Rc`], any weak references created beforehand will + /// point to the new [`Rc`]. + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn new(value: T) -> Self { + Self { + ptr: Box::leak(Box::new(RcBox { + strong: Cell::new(0), + // keep one weak reference so if all the weak pointers that are created are dropped + // the UniqueRc still stays valid. + weak: Cell::new(1), + value, + })) + .into(), + phantom: PhantomData, + } + } + + /// Creates a new weak reference to the `UniqueRc` + /// + /// Attempting to upgrade this weak reference will fail before the `UniqueRc` has been converted + /// to a [`Rc`] using [`UniqueRc::into_rc`]. + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn downgrade(this: &Self) -> Weak<T> { + // SAFETY: This pointer was allocated at creation time and we guarantee that we only have + // one strong reference before converting to a regular Rc. + unsafe { + this.ptr.as_ref().inc_weak(); + } + Weak { ptr: this.ptr } + } + + /// Converts the `UniqueRc` into a regular [`Rc`] + /// + /// This consumes the `UniqueRc` and returns a regular [`Rc`] that contains the `value` that + /// is passed to `into_rc`. + /// + /// Any weak references created before this method is called can now be upgraded to strong + /// references. + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn into_rc(this: Self) -> Rc<T> { + let mut this = ManuallyDrop::new(this); + // SAFETY: This pointer was allocated at creation time so we know it is valid. + unsafe { + // Convert our weak reference into a strong reference + this.ptr.as_mut().strong.set(1); + Rc::from_inner(this.ptr) + } + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl<T> Deref for UniqueRc<T> { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: This pointer was allocated at creation time so we know it is valid. + unsafe { &self.ptr.as_ref().value } + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl<T> DerefMut for UniqueRc<T> { + fn deref_mut(&mut self) -> &mut T { + // SAFETY: This pointer was allocated at creation time so we know it is valid. We know we + // have unique ownership and therefore it's safe to make a mutable reference because + // `UniqueRc` owns the only strong reference to itself. + unsafe { &mut (*self.ptr.as_ptr()).value } + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +unsafe impl<#[may_dangle] T> Drop for UniqueRc<T> { + fn drop(&mut self) { + unsafe { + // destroy the contained object + drop_in_place(DerefMut::deref_mut(self)); + + // remove the implicit "strong weak" pointer now that we've destroyed the contents. + self.ptr.as_ref().dec_weak(); + + if self.ptr.as_ref().weak() == 0 { + Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); + } + } + } +} diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs index 2784108e0e6..1f221b86f12 100644 --- a/library/alloc/src/rc/tests.rs +++ b/library/alloc/src/rc/tests.rs @@ -574,3 +574,48 @@ fn test_rc_cyclic_with_two_ref() { assert_eq!(Rc::strong_count(&two_refs), 3); assert_eq!(Rc::weak_count(&two_refs), 2); } + +#[test] +fn test_unique_rc_weak() { + let rc = UniqueRc::new(42); + let weak = UniqueRc::downgrade(&rc); + assert!(weak.upgrade().is_none()); + + let _rc = UniqueRc::into_rc(rc); + assert_eq!(*weak.upgrade().unwrap(), 42); +} + +#[test] +fn test_unique_rc_drop_weak() { + let rc = UniqueRc::new(42); + let weak = UniqueRc::downgrade(&rc); + mem::drop(weak); + + let rc = UniqueRc::into_rc(rc); + assert_eq!(*rc, 42); +} + +#[test] +fn test_unique_rc_drops_contents() { + let mut dropped = false; + struct DropMe<'a>(&'a mut bool); + impl Drop for DropMe<'_> { + fn drop(&mut self) { + *self.0 = true; + } + } + { + let rc = UniqueRc::new(DropMe(&mut dropped)); + drop(rc); + } + assert!(dropped); +} + +#[test] +fn test_unique_rc_weak_clone_holding_ref() { + let mut v = UniqueRc::new(0u8); + let w = UniqueRc::downgrade(&v); + let r = &mut *v; + let _ = w.clone(); // touch weak count + *r = 123; +} diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index d2c87cf705c..5bb1a93aeaf 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1267,7 +1267,7 @@ impl<T: ?Sized> Arc<T> { } /// Returns `true` if the two `Arc`s point to the same allocation in a vein similar to - /// [`ptr::eq`]. See [that function][`ptr::eq`] for caveats when comparing `dyn Trait` pointers. + /// [`ptr::eq`]. This function ignores the metadata of `dyn Trait` pointers. /// /// # Examples /// @@ -1287,7 +1287,7 @@ impl<T: ?Sized> Arc<T> { #[must_use] #[stable(feature = "ptr_eq", since = "1.17.0")] pub fn ptr_eq(this: &Self, other: &Self) -> bool { - this.ptr.as_ptr() == other.ptr.as_ptr() + this.ptr.as_ptr() as *const () == other.ptr.as_ptr() as *const () } } @@ -2254,8 +2254,8 @@ impl<T: ?Sized> Weak<T> { } /// Returns `true` if the two `Weak`s point to the same allocation similar to [`ptr::eq`], or if - /// both don't point to any allocation (because they were created with `Weak::new()`). See [that - /// function][`ptr::eq`] for caveats when comparing `dyn Trait` pointers. + /// both don't point to any allocation (because they were created with `Weak::new()`). However, + /// this function ignores the metadata of `dyn Trait` pointers. /// /// # Notes /// @@ -2298,7 +2298,7 @@ impl<T: ?Sized> Weak<T> { #[must_use] #[stable(feature = "weak_ptr_eq", since = "1.39.0")] pub fn ptr_eq(&self, other: &Self) -> bool { - self.ptr.as_ptr() == other.ptr.as_ptr() + ptr::eq(self.ptr.as_ptr() as *const (), other.ptr.as_ptr() as *const ()) } } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 289bbc7d2ef..a30c6a44e07 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2978,9 +2978,14 @@ impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec<T, A> { /// Implements comparison of vectors, [lexicographically](Ord#lexicographical-comparison). #[stable(feature = "rust1", since = "1.0.0")] -impl<T: PartialOrd, A: Allocator> PartialOrd for Vec<T, A> { +impl<T, A1, A2> PartialOrd<Vec<T, A2>> for Vec<T, A1> +where + T: PartialOrd, + A1: Allocator, + A2: Allocator, +{ #[inline] - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + fn partial_cmp(&self, other: &Vec<T, A2>) -> Option<Ordering> { PartialOrd::partial_cmp(&**self, &**other) } } diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index c1cc892eb86..909b32547e7 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1374,7 +1374,7 @@ impl Clone for BorrowRef<'_> { debug_assert!(is_reading(borrow)); // Prevent the borrow counter from overflowing into // a writing borrow. - assert!(borrow != isize::MAX); + assert!(borrow != BorrowFlag::MAX); self.borrow.set(borrow + 1); BorrowRef { borrow: self.borrow } } @@ -1756,7 +1756,7 @@ impl<'b> BorrowRefMut<'b> { let borrow = self.borrow.get(); debug_assert!(is_writing(borrow)); // Prevent the borrow counter from underflowing. - assert!(borrow != isize::MIN); + assert!(borrow != BorrowFlag::MIN); self.borrow.set(borrow - 1); BorrowRefMut { borrow: self.borrow } } diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 86ea154a886..7437722fd06 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -238,7 +238,7 @@ impl fmt::Debug for c_void { not(target_arch = "s390x"), not(target_arch = "x86_64") ), - all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")), + all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios", target_os = "tvos")), target_family = "wasm", target_arch = "asmjs", target_os = "uefi", @@ -267,7 +267,7 @@ pub struct VaListImpl<'f> { not(target_arch = "s390x"), not(target_arch = "x86_64") ), - all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")), + all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios", target_os = "tvos")), target_family = "wasm", target_arch = "asmjs", target_os = "uefi", @@ -292,7 +292,7 @@ impl<'f> fmt::Debug for VaListImpl<'f> { /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf #[cfg(all( target_arch = "aarch64", - not(any(target_os = "macos", target_os = "ios")), + not(any(target_os = "macos", target_os = "ios", target_os = "tvos")), not(target_os = "uefi"), not(windows), ))] @@ -389,7 +389,10 @@ pub struct VaList<'a, 'f: 'a> { not(target_arch = "s390x"), not(target_arch = "x86_64") ), - all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")), + all( + target_arch = "aarch64", + any(target_os = "macos", target_os = "ios", target_os = "tvos") + ), target_family = "wasm", target_arch = "asmjs", target_os = "uefi", @@ -404,7 +407,10 @@ pub struct VaList<'a, 'f: 'a> { target_arch = "s390x", target_arch = "x86_64" ), - any(not(target_arch = "aarch64"), not(any(target_os = "macos", target_os = "ios"))), + any( + not(target_arch = "aarch64"), + not(any(target_os = "macos", target_os = "ios", target_os = "tvos")) + ), not(target_family = "wasm"), not(target_arch = "asmjs"), not(target_os = "uefi"), @@ -422,7 +428,7 @@ pub struct VaList<'a, 'f: 'a> { not(target_arch = "s390x"), not(target_arch = "x86_64") ), - all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")), + all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios", target_os = "tvos")), target_family = "wasm", target_arch = "asmjs", target_os = "uefi", @@ -449,7 +455,10 @@ impl<'f> VaListImpl<'f> { target_arch = "s390x", target_arch = "x86_64" ), - any(not(target_arch = "aarch64"), not(any(target_os = "macos", target_os = "ios"))), + any( + not(target_arch = "aarch64"), + not(any(target_os = "macos", target_os = "ios", target_os = "tvos")) + ), not(target_family = "wasm"), not(target_arch = "asmjs"), not(target_os = "uefi"), diff --git a/library/core/src/future/poll_fn.rs b/library/core/src/future/poll_fn.rs index 90cb797391a..d27a9dfc176 100644 --- a/library/core/src/future/poll_fn.rs +++ b/library/core/src/future/poll_fn.rs @@ -24,6 +24,93 @@ use crate::task::{Context, Poll}; /// assert_eq!(read_future.await, "Hello, World!".to_owned()); /// # } /// ``` +/// +/// ## Capturing a pinned state +/// +/// Example of a closure wrapping inner futures: +/// +/// ``` +/// # async fn run() { +/// use core::future::{self, Future}; +/// use core::task::Poll; +/// +/// /// Resolves to the first future that completes. In the event of a tie, `a` wins. +/// fn naive_select<T>( +/// a: impl Future<Output = T>, +/// b: impl Future<Output = T>, +/// ) -> impl Future<Output = T> +/// { +/// let (mut a, mut b) = (Box::pin(a), Box::pin(b)); +/// future::poll_fn(move |cx| { +/// if let Poll::Ready(r) = a.as_mut().poll(cx) { +/// Poll::Ready(r) +/// } else if let Poll::Ready(r) = b.as_mut().poll(cx) { +/// Poll::Ready(r) +/// } else { +/// Poll::Pending +/// } +/// }) +/// } +/// +/// let a = async { 42 }; +/// let b = future::pending(); +/// let v = naive_select(a, b).await; +/// assert_eq!(v, 42); +/// +/// let a = future::pending(); +/// let b = async { 27 }; +/// let v = naive_select(a, b).await; +/// assert_eq!(v, 27); +/// +/// let a = async { 42 }; +/// let b = async { 27 }; +/// let v = naive_select(a, b).await; +/// assert_eq!(v, 42); // biased towards `a` in case of tie! +/// # } +/// ``` +/// +/// This time without [`Box::pin`]ning: +/// +/// [`Box::pin`]: ../../std/boxed/struct.Box.html#method.pin +/// +/// ``` +/// # async fn run() { +/// use core::future::{self, Future}; +/// use core::pin::pin; +/// use core::task::Poll; +/// +/// /// Resolves to the first future that completes. In the event of a tie, `a` wins. +/// fn naive_select<T>( +/// a: impl Future<Output = T>, +/// b: impl Future<Output = T>, +/// ) -> impl Future<Output = T> +/// { +/// async { +/// let (mut a, mut b) = (pin!(a), pin!(b)); +/// future::poll_fn(move |cx| { +/// if let Poll::Ready(r) = a.as_mut().poll(cx) { +/// Poll::Ready(r) +/// } else if let Poll::Ready(r) = b.as_mut().poll(cx) { +/// Poll::Ready(r) +/// } else { +/// Poll::Pending +/// } +/// }).await +/// } +/// } +/// +/// let a = async { 42 }; +/// let b = future::pending(); +/// let v = naive_select(a, b).await; +/// assert_eq!(v, 42); +/// # } +/// ``` +/// +/// - Notice how, by virtue of being in an `async` context, we have been able to make the [`pin!`] +/// macro work, thereby avoiding any need for the `unsafe` +/// <code>[Pin::new_unchecked](&mut fut)</code> constructor. +/// +/// [`pin!`]: crate::pin::pin! #[stable(feature = "future_poll_fn", since = "1.64.0")] pub fn poll_fn<T, F>(f: F) -> PollFn<F> where diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 9a541ccaeac..760e58276fc 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -140,7 +140,8 @@ unsafe impl<T: Sync + ?Sized> Send for &T {} )] #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable #[rustc_specialization_trait] -#[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] #[rustc_coinductive] pub trait Sized { // Empty. @@ -173,7 +174,8 @@ pub trait Sized { /// [nomicon-coerce]: ../../nomicon/coercions.html #[unstable(feature = "unsize", issue = "18598")] #[lang = "unsize"] -#[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub trait Unsize<T: ?Sized> { // Empty. } @@ -854,7 +856,8 @@ impl<T: ?Sized> StructuralEq for PhantomData<T> {} reason = "this trait is unlikely to ever be stabilized, use `mem::discriminant` instead" )] #[lang = "discriminant_kind"] -#[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub trait DiscriminantKind { /// The type of the discriminant, which must satisfy the trait /// bounds required by `mem::Discriminant`. @@ -959,7 +962,8 @@ marker_impls! { #[unstable(feature = "const_trait_impl", issue = "67792")] #[lang = "destruct"] #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] -#[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] #[const_trait] pub trait Destruct {} @@ -970,7 +974,8 @@ pub trait Destruct {} #[unstable(feature = "tuple_trait", issue = "none")] #[lang = "tuple_trait"] #[rustc_on_unimplemented(message = "`{Self}` is not a tuple")] -#[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub trait Tuple {} /// A marker for pointer-like types. @@ -1025,7 +1030,8 @@ impl ConstParamTy for () {} reason = "internal trait for implementing various traits for all function pointers" )] #[lang = "fn_ptr_trait"] -#[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub trait FnPtr: Copy + Clone { /// Returns the address of the function pointer. #[lang = "fn_ptr_addr"] diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 39c9a04eea9..2fff3f0efd7 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1317,7 +1317,8 @@ impl<T> SizedTypeProperties for T {} /// assert_eq!(mem::offset_of!(NestedA, b.0), 0); /// ``` #[unstable(feature = "offset_of", issue = "106655")] -#[allow_internal_unstable(builtin_syntax)] +#[allow_internal_unstable(builtin_syntax, hint_must_use)] pub macro offset_of($Container:ty, $($fields:tt).+ $(,)?) { - builtin # offset_of($Container, $($fields).+) + // The `{}` is for better error messages + crate::hint::must_use({builtin # offset_of($Container, $($fields).+)}) } diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index a6f792ed0e3..3805d149b70 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -7,6 +7,8 @@ use crate::marker::ConstParamTy; /// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied. #[unstable(feature = "transmutability", issue = "99571")] #[lang = "transmute_trait"] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub unsafe trait BikeshedIntrinsicFrom<Src, Context, const ASSUME: Assume = { Assume::NOTHING }> where Src: ?Sized, diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 954d88d548e..c51913fa8ab 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -1770,14 +1770,8 @@ impl fmt::Display for Ipv6Addr { f.write_str("::") } else if self.is_loopback() { f.write_str("::1") - } else if let Some(ipv4) = self.to_ipv4() { - match segments[5] { - // IPv4 Compatible address - 0 => write!(f, "::{}", ipv4), - // IPv4 Mapped address - 0xffff => write!(f, "::ffff:{}", ipv4), - _ => unreachable!(), - } + } else if let Some(ipv4) = self.to_ipv4_mapped() { + write!(f, "::ffff:{}", ipv4) } else { #[derive(Copy, Clone, Default)] struct Span { diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index c9baa09f407..95dcaf5dd73 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -3,7 +3,6 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::ascii; -use crate::convert::TryInto; use crate::intrinsics; use crate::mem; use crate::ops::{Add, Mul, Sub}; @@ -278,18 +277,12 @@ macro_rules! widening_impl { macro_rules! conv_rhs_for_unchecked_shift { ($SelfT:ty, $x:expr) => {{ - #[inline] - fn conv(x: u32) -> $SelfT { - // FIXME(const-hack) replace with `.try_into().ok().unwrap_unchecked()`. - // SAFETY: Any legal shift amount must be losslessly representable in the self type. - unsafe { x.try_into().ok().unwrap_unchecked() } - } - #[inline] - const fn const_conv(x: u32) -> $SelfT { - x as _ + // If the `as` cast will truncate, ensure we still tell the backend + // that the pre-truncation value was also small. + if <$SelfT>::BITS < 32 { + intrinsics::assume($x <= (<$SelfT>::MAX as u32)); } - - intrinsics::const_eval_select(($x,), const_conv, conv) + $x as $SelfT }}; } diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 2ea032d4aff..daaa44b1d9a 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -50,7 +50,8 @@ use crate::hash::{Hash, Hasher}; /// /// [`to_raw_parts`]: *const::to_raw_parts #[lang = "pointee_trait"] -#[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub trait Pointee { /// The type for metadata in pointers and references to `Self`. #[lang = "metadata_type"] diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs index 052fd34d0b6..48a6eb03b5e 100644 --- a/library/core/src/slice/raw.rs +++ b/library/core/src/slice/raw.rs @@ -32,7 +32,8 @@ use crate::ptr; /// * The memory referenced by the returned slice must not be mutated for the duration /// of lifetime `'a`, except inside an `UnsafeCell`. /// -/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`. +/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. /// See the safety documentation of [`pointer::offset`]. /// /// # Caveat @@ -125,7 +126,8 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] /// (not derived from the return value) for the duration of lifetime `'a`. /// Both read and write accesses are forbidden. /// -/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`. +/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. /// See the safety documentation of [`pointer::offset`]. /// /// [valid]: ptr#safety @@ -179,15 +181,16 @@ pub const fn from_mut<T>(s: &mut T) -> &mut [T] { /// the last element, such that the offset from the end to the start pointer is /// the length of the slice. /// -/// * The range must contain `N` consecutive properly initialized values of type `T`: +/// * The entire memory range of this slice must be contained within a single allocated object! +/// Slices can never span across multiple allocated objects. /// -/// * The entire memory range of this slice must be contained within a single allocated object! -/// Slices can never span across multiple allocated objects. +/// * The range must contain `N` consecutive properly initialized values of type `T`. /// /// * The memory referenced by the returned slice must not be mutated for the duration /// of lifetime `'a`, except inside an `UnsafeCell`. /// -/// * The total length of the range must be no larger than `isize::MAX`. +/// * The total length of the range must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. /// See the safety documentation of [`pointer::offset`]. /// /// Note that a range created from [`slice::as_ptr_range`] fulfills these requirements. @@ -247,16 +250,17 @@ pub const unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] { /// the last element, such that the offset from the end to the start pointer is /// the length of the slice. /// -/// * The range must contain `N` consecutive properly initialized values of type `T`: +/// * The entire memory range of this slice must be contained within a single allocated object! +/// Slices can never span across multiple allocated objects. /// -/// * The entire memory range of this slice must be contained within a single allocated object! -/// Slices can never span across multiple allocated objects. +/// * The range must contain `N` consecutive properly initialized values of type `T`. /// /// * The memory referenced by the returned slice must not be accessed through any other pointer /// (not derived from the return value) for the duration of lifetime `'a`. /// Both read and write accesses are forbidden. /// -/// * The total length of the range must be no larger than `isize::MAX`. +/// * The total length of the range must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. /// See the safety documentation of [`pointer::offset`]. /// /// Note that a range created from [`slice::as_mut_ptr_range`] fulfills these requirements. diff --git a/library/core/src/unicode/printable.py b/library/core/src/unicode/printable.py index 7c37f5f099c..4d39ace066c 100755 --- a/library/core/src/unicode/printable.py +++ b/library/core/src/unicode/printable.py @@ -119,7 +119,7 @@ def print_singletons(uppers, lowers, uppersname, lowersname): print("#[rustfmt::skip]") print("const {}: &[u8] = &[".format(lowersname)) for i in range(0, len(lowers), 8): - print(" {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8]))) + print(" {}".format(" ".join("{:#04x},".format(x) for x in lowers[i:i+8]))) print("];") def print_normal(normal, normalname): diff --git a/library/core/tests/net/ip_addr.rs b/library/core/tests/net/ip_addr.rs index 5a6ac08c088..7530fc08487 100644 --- a/library/core/tests/net/ip_addr.rs +++ b/library/core/tests/net/ip_addr.rs @@ -139,7 +139,7 @@ fn ipv6_addr_to_string() { // ipv4-compatible address let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280); - assert_eq!(a1.to_string(), "::192.0.2.128"); + assert_eq!(a1.to_string(), "::c000:280"); // v6 address with no zero segments assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f"); @@ -316,7 +316,7 @@ fn ip_properties() { check!("::", unspec); check!("::1", loopback); - check!("::0.0.0.2", global); + check!("::2", global); check!("1::", global); check!("fc00::"); check!("fdff:ffff::"); @@ -607,7 +607,7 @@ fn ipv6_properties() { check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback); - check!("::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global); + check!("::2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global); check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global); diff --git a/library/core/tests/net/socket_addr.rs b/library/core/tests/net/socket_addr.rs index 68c7cd94d32..35a69cead48 100644 --- a/library/core/tests/net/socket_addr.rs +++ b/library/core/tests/net/socket_addr.rs @@ -34,7 +34,7 @@ fn ipv6_socket_addr_to_string() { // IPv4-compatible address. assert_eq!( SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280), 8080, 0, 0).to_string(), - "[::192.0.2.128]:8080" + "[::c000:280]:8080" ); // IPv6 address with no zero segments. diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index af74efa6bf8..aaaa88624f0 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -18,7 +18,7 @@ panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } libc = { version = "0.2.146", default-features = false, features = ['rustc-dep-of-std'], public = true } -compiler_builtins = { version = "0.1.92" } +compiler_builtins = { version = "0.1.93" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.14", default-features = false, features = ['rustc-dep-of-std'] } diff --git a/library/std/build.rs b/library/std/build.rs index d0b37940936..ddf6e84d8d0 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -18,6 +18,7 @@ fn main() { || target.contains("illumos") || target.contains("apple-darwin") || target.contains("apple-ios") + || target.contains("apple-tvos") || target.contains("apple-watchos") || target.contains("uwp") || target.contains("windows") @@ -48,7 +49,6 @@ fn main() { // - mipsel-sony-psp // - nvptx64-nvidia-cuda // - arch=avr - // - tvos (aarch64-apple-tvos, x86_64-apple-tvos) // - uefi (x86_64-unknown-uefi, i686-unknown-uefi) // - JSON targets // - Any new targets that have not been explicitly added above. diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index e2480bcbbc7..9ff01b9c35d 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1640,6 +1640,10 @@ fn test_file_times() { use crate::os::ios::fs::FileTimesExt; #[cfg(target_os = "macos")] use crate::os::macos::fs::FileTimesExt; + #[cfg(target_os = "tvos")] + use crate::os::tvos::fs::FileTimesExt; + #[cfg(target_os = "tvos")] + use crate::os::tvos::fs::FileTimesExt; #[cfg(target_os = "watchos")] use crate::os::watchos::fs::FileTimesExt; #[cfg(windows)] @@ -1651,9 +1655,21 @@ fn test_file_times() { let accessed = SystemTime::UNIX_EPOCH + Duration::from_secs(12345); let modified = SystemTime::UNIX_EPOCH + Duration::from_secs(54321); times = times.set_accessed(accessed).set_modified(modified); - #[cfg(any(windows, target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any( + windows, + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "tvos", + ))] let created = SystemTime::UNIX_EPOCH + Duration::from_secs(32123); - #[cfg(any(windows, target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any( + windows, + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "tvos", + ))] { times = times.set_created(created); } @@ -1678,7 +1694,13 @@ fn test_file_times() { let metadata = file.metadata().unwrap(); assert_eq!(metadata.accessed().unwrap(), accessed); assert_eq!(metadata.modified().unwrap(), modified); - #[cfg(any(windows, target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any( + windows, + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "tvos", + ))] { assert_eq!(metadata.created().unwrap(), created); } diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index fcc5cfafd80..ba1b8cbfa56 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -154,7 +154,7 @@ macro_rules! println { /// /// Panics if writing to `io::stderr` fails. /// -/// Writing to non-blocking stdout can cause an error, which will lead +/// Writing to non-blocking stderr can cause an error, which will lead /// this macro to panic. /// /// # Examples @@ -189,7 +189,7 @@ macro_rules! eprint { /// /// Panics if writing to `io::stderr` fails. /// -/// Writing to non-blocking stdout can cause an error, which will lead +/// Writing to non-blocking stderr can cause an error, which will lead /// this macro to panic. /// /// # Examples diff --git a/library/std/src/net/socket_addr/tests.rs b/library/std/src/net/socket_addr/tests.rs index dfc6dabbed1..6a065cfba21 100644 --- a/library/std/src/net/socket_addr/tests.rs +++ b/library/std/src/net/socket_addr/tests.rs @@ -85,7 +85,7 @@ fn ipv6_socket_addr_to_string() { // IPv4-compatible address. assert_eq!( SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280), 8080, 0, 0).to_string(), - "[::192.0.2.128]:8080" + "[::c000:280]:8080" ); // IPv6 address with no zero segments. diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index 7a3c66e4504..db367cfa0f7 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -47,6 +47,17 @@ fn connect_error() { } #[test] +#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 +fn connect_timeout_error() { + let socket_addr = next_test_ip4(); + let result = TcpStream::connect_timeout(&socket_addr, Duration::MAX); + assert!(!matches!(result, Err(e) if e.kind() == ErrorKind::TimedOut)); + + let _listener = TcpListener::bind(&socket_addr).unwrap(); + assert!(TcpStream::connect_timeout(&socket_addr, Duration::MAX).is_ok()); +} + +#[test] fn listen_localhost() { let socket_addr = next_test_ip4(); let listener = t!(TcpListener::bind(&socket_addr)); diff --git a/library/std/src/os/ios/fs.rs b/library/std/src/os/ios/fs.rs index 6d4d54b7c78..b319527a541 100644 --- a/library/std/src/os/ios/fs.rs +++ b/library/std/src/os/ios/fs.rs @@ -6,7 +6,7 @@ use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; use crate::time::SystemTime; #[allow(deprecated)] -use crate::os::ios::raw; +use super::raw; /// OS-specific extensions to [`fs::Metadata`]. /// diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index 5b54cc5f2e4..634c3cc4a15 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -137,6 +137,9 @@ pub mod redox; pub mod solaris; #[cfg(target_os = "solid_asp3")] pub mod solid; +#[cfg(target_os = "tvos")] +#[path = "ios/mod.rs"] +pub(crate) mod tvos; #[cfg(target_os = "vita")] pub mod vita; #[cfg(target_os = "vxworks")] diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs index 6fe1111188a..401ec1e7a01 100644 --- a/library/std/src/os/unix/mod.rs +++ b/library/std/src/os/unix/mod.rs @@ -73,6 +73,8 @@ mod platform { pub use crate::os::redox::*; #[cfg(target_os = "solaris")] pub use crate::os::solaris::*; + #[cfg(target_os = "tvos")] + pub use crate::os::tvos::*; #[cfg(target_os = "vita")] pub use crate::os::vita::*; #[cfg(target_os = "vxworks")] @@ -96,6 +98,7 @@ pub mod thread; target_os = "dragonfly", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "macos", target_os = "netbsd", diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index bf2a51b5edb..e20170873bb 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -11,6 +11,7 @@ use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, Owned target_os = "dragonfly", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "macos", target_os = "watchos", target_os = "netbsd", @@ -30,6 +31,7 @@ use crate::time::Duration; target_os = "dragonfly", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "macos", target_os = "watchos", target_os = "netbsd", @@ -238,6 +240,7 @@ impl UnixStream { target_os = "dragonfly", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "macos", target_os = "watchos", target_os = "netbsd", diff --git a/library/std/src/os/unix/ucred.rs b/library/std/src/os/unix/ucred.rs index 95967eac295..6a0cc2d2c48 100644 --- a/library/std/src/os/unix/ucred.rs +++ b/library/std/src/os/unix/ucred.rs @@ -36,7 +36,7 @@ pub use self::impl_linux::peer_cred; ))] pub use self::impl_bsd::peer_cred; -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] pub use self::impl_mac::peer_cred; #[cfg(any(target_os = "linux", target_os = "android"))] @@ -98,7 +98,7 @@ pub mod impl_bsd { } } -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] pub mod impl_mac { use super::UCred; use crate::os::unix::io::AsRawFd; diff --git a/library/std/src/os/unix/ucred/tests.rs b/library/std/src/os/unix/ucred/tests.rs index e63a2fc248e..dd99ecdd819 100644 --- a/library/std/src/os/unix/ucred/tests.rs +++ b/library/std/src/os/unix/ucred/tests.rs @@ -8,6 +8,7 @@ use libc::{getegid, geteuid, getpid}; target_os = "dragonfly", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "macos", target_os = "watchos", target_os = "openbsd" @@ -26,7 +27,13 @@ fn test_socket_pair() { } #[test] -#[cfg(any(target_os = "linux", target_os = "ios", target_os = "macos", target_os = "watchos"))] +#[cfg(any( + target_os = "linux", + target_os = "ios", + target_os = "macos", + target_os = "watchos", + target_os = "tvos", +))] fn test_socket_pair_pids(arg: Type) -> RetType { // Create two connected sockets and get their peer credentials. let (sock_a, sock_b) = UnixStream::pair().unwrap(); diff --git a/library/std/src/personality/gcc.rs b/library/std/src/personality/gcc.rs index 82edb11cbd1..6552d96ca69 100644 --- a/library/std/src/personality/gcc.rs +++ b/library/std/src/personality/gcc.rs @@ -85,7 +85,7 @@ const UNWIND_DATA_REG: (i32, i32) = (4, 5); // a0, a1 // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c cfg_if::cfg_if! { - if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "watchos"), not(target_os = "netbsd")))] { + if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "tvos"), not(target_os = "watchos"), not(target_os = "netbsd")))] { // ARM EHABI personality routine. // https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf // diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index 0e0c87d1c74..71ff4237d00 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -347,8 +347,8 @@ pub struct Sender<T> { #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<T: Send> Send for Sender<T> {} -#[stable(feature = "rust1", since = "1.0.0")] -impl<T> !Sync for Sender<T> {} +#[stable(feature = "mpsc_sender_sync", since = "CURRENT_RUSTC_VERSION")] +unsafe impl<T: Send> Sync for Sender<T> {} /// The sending-half of Rust's synchronous [`sync_channel`] type. /// diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs index 0efe2570d67..f8fa81e6ef1 100644 --- a/library/std/src/sys/unix/args.rs +++ b/library/std/src/sys/unix/args.rs @@ -168,7 +168,7 @@ mod imp { } } -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] mod imp { use super::Args; use crate::ffi::CStr; @@ -209,7 +209,7 @@ mod imp { // for i in (0..[args count]) // res.push([args objectAtIndex:i]) // res - #[cfg(any(target_os = "ios", target_os = "watchos"))] + #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))] pub fn args() -> Args { use crate::ffi::OsString; use crate::mem; diff --git a/library/std/src/sys/unix/env.rs b/library/std/src/sys/unix/env.rs index 8c3ef88d8f8..929e9dae738 100644 --- a/library/std/src/sys/unix/env.rs +++ b/library/std/src/sys/unix/env.rs @@ -31,6 +31,17 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } +#[cfg(target_os = "tvos")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "tvos"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".dylib"; + pub const DLL_EXTENSION: &str = "dylib"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + #[cfg(target_os = "watchos")] pub mod os { pub const FAMILY: &str = "unix"; diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 69c93c92003..85e020ae413 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -44,6 +44,7 @@ const READ_LIMIT: usize = libc::ssize_t::MAX as usize; target_os = "dragonfly", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "macos", target_os = "netbsd", target_os = "openbsd", @@ -69,6 +70,7 @@ const fn max_iov() -> usize { target_os = "emscripten", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -181,6 +183,7 @@ impl FileDesc { target_os = "fuchsia", target_os = "illumos", target_os = "ios", + target_os = "tvos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -222,6 +225,7 @@ impl FileDesc { #[cfg(any( all(target_os = "android", target_pointer_width = "32"), target_os = "ios", + target_os = "tvos", target_os = "macos", ))] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { @@ -320,6 +324,7 @@ impl FileDesc { target_os = "fuchsia", target_os = "illumos", target_os = "ios", + target_os = "tvos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -361,6 +366,7 @@ impl FileDesc { #[cfg(any( all(target_os = "android", target_pointer_width = "32"), target_os = "ios", + target_os = "tvos", target_os = "macos", ))] pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index d2fb6238387..9cf5cfcc8d5 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -32,6 +32,7 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; all(target_os = "linux", target_env = "gnu"), target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", ))] use crate::sys::weak::syscall; @@ -43,6 +44,7 @@ use libc::{c_int, mode_t}; #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "solaris", all(target_os = "linux", target_env = "gnu") @@ -360,7 +362,7 @@ pub struct FilePermissions { pub struct FileTimes { accessed: Option<SystemTime>, modified: Option<SystemTime>, - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "tvos"))] created: Option<SystemTime>, } @@ -519,6 +521,7 @@ impl FileAttr { target_os = "openbsd", target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", ))] pub fn created(&self) -> io::Result<SystemTime> { @@ -530,6 +533,7 @@ impl FileAttr { target_os = "openbsd", target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "vita", )))] @@ -611,7 +615,7 @@ impl FileTimes { self.modified = Some(t); } - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "tvos"))] pub fn set_created(&mut self, t: SystemTime) { self.created = Some(t); } @@ -895,6 +899,7 @@ impl DirEntry { #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "linux", target_os = "emscripten", @@ -928,6 +933,7 @@ impl DirEntry { #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "netbsd", target_os = "openbsd", @@ -946,6 +952,7 @@ impl DirEntry { #[cfg(not(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "netbsd", target_os = "openbsd", @@ -1107,11 +1114,21 @@ impl File { cvt_r(|| unsafe { os_fsync(self.as_raw_fd()) })?; return Ok(()); - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", + ))] unsafe fn os_fsync(fd: c_int) -> c_int { libc::fcntl(fd, libc::F_FULLFSYNC) } - #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "watchos")))] + #[cfg(not(any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", + )))] unsafe fn os_fsync(fd: c_int) -> c_int { libc::fsync(fd) } @@ -1121,7 +1138,12 @@ impl File { cvt_r(|| unsafe { os_datasync(self.as_raw_fd()) })?; return Ok(()); - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", + ))] unsafe fn os_datasync(fd: c_int) -> c_int { libc::fcntl(fd, libc::F_FULLFSYNC) } @@ -1140,6 +1162,7 @@ impl File { target_os = "android", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -1249,7 +1272,7 @@ impl File { io::ErrorKind::Unsupported, "setting file times not supported", )) - } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] { + } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] { let mut buf = [mem::MaybeUninit::<libc::timespec>::uninit(); 3]; let mut num_times = 0; let mut attrlist: libc::attrlist = unsafe { mem::zeroed() }; @@ -1709,6 +1732,7 @@ fn open_to_and_set_permissions( target_os = "android", target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", )))] pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { @@ -1736,7 +1760,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { } } -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { use crate::sync::atomic::{AtomicBool, Ordering}; diff --git a/library/std/src/sys/unix/locks/pthread_condvar.rs b/library/std/src/sys/unix/locks/pthread_condvar.rs index 192fa216dfa..2dc1b0c601e 100644 --- a/library/std/src/sys/unix/locks/pthread_condvar.rs +++ b/library/std/src/sys/unix/locks/pthread_condvar.rs @@ -32,6 +32,7 @@ impl LazyInit for AllocatedCondvar { if #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "l4re", target_os = "android", @@ -124,6 +125,7 @@ impl Condvar { #[cfg(not(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "android", target_os = "espidf", @@ -158,6 +160,7 @@ impl Condvar { #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "android", target_os = "espidf", diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 24566d96bcd..1b72e21a832 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -87,6 +87,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { // The poll on Darwin doesn't set POLLNVAL for closed fds. target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "redox", target_os = "l4re", @@ -387,7 +388,7 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "macos")] { #[link(name = "System")] extern "C" {} - } else if #[cfg(any(target_os = "ios", target_os = "watchos"))] { + } else if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))] { #[link(name = "System")] #[link(name = "objc")] #[link(name = "Security", kind = "framework")] diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index 8edfd331304..a68c14758ff 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -63,7 +63,13 @@ extern "C" { #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), link_name = "___errno")] #[cfg_attr(target_os = "nto", link_name = "__get_errno_ptr")] #[cfg_attr( - any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "watchos"), + any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "freebsd", + target_os = "watchos" + ), link_name = "__error" )] #[cfg_attr(target_os = "haiku", link_name = "_errnop")] @@ -375,7 +381,7 @@ pub fn current_exe() -> io::Result<PathBuf> { Ok(PathBuf::from(OsString::from_vec(e))) } -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] pub fn current_exe() -> io::Result<PathBuf> { unsafe { let mut sz: u32 = 0; @@ -609,6 +615,7 @@ pub fn home_dir() -> Option<PathBuf> { #[cfg(any( target_os = "android", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "emscripten", target_os = "redox", @@ -623,6 +630,7 @@ pub fn home_dir() -> Option<PathBuf> { #[cfg(not(any( target_os = "android", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "emscripten", target_os = "redox", diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 22d9d6141f4..129e7643661 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -15,6 +15,8 @@ use crate::sys::weak::raw_syscall; #[cfg(any( target_os = "macos", + target_os = "watchos", + target_os = "tvos", target_os = "freebsd", all(target_os = "linux", target_env = "gnu"), all(target_os = "linux", target_env = "musl"), @@ -28,7 +30,12 @@ use libc::RTP_ID as pid_t; #[cfg(not(target_os = "vxworks"))] use libc::{c_int, pid_t}; -#[cfg(not(any(target_os = "vxworks", target_os = "l4re")))] +#[cfg(not(any( + target_os = "vxworks", + target_os = "l4re", + target_os = "tvos", + target_os = "watchos", +)))] use libc::{gid_t, uid_t}; cfg_if::cfg_if! { @@ -84,7 +91,6 @@ impl Command { if let Some(ret) = self.posix_spawn(&theirs, envp.as_ref())? { return Ok((ret, ours)); } - let (input, output) = sys::pipe::anon_pipe()?; // Whatever happens after the fork is almost for sure going to touch or @@ -166,9 +172,31 @@ impl Command { crate::sys_common::process::wait_with_output(proc, pipes) } + // WatchOS and TVOS headers mark the `fork`/`exec*` functions with + // `__WATCHOS_PROHIBITED __TVOS_PROHIBITED`, and indicate that the + // `posix_spawn*` functions should be used instead. It isn't entirely clear + // what `PROHIBITED` means here (e.g. if calls to these functions are + // allowed to exist in dead code), but it sounds bad, so we go out of our + // way to avoid that all-together. + #[cfg(any(target_os = "tvos", target_os = "watchos"))] + const ERR_APPLE_TV_WATCH_NO_FORK_EXEC: Error = io::const_io_error!( + ErrorKind::Unsupported, + "`fork`+`exec`-based process spawning is not supported on this target", + ); + + #[cfg(any(target_os = "tvos", target_os = "watchos"))] + unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> { + return Err(Self::ERR_APPLE_TV_WATCH_NO_FORK_EXEC); + } + // Attempts to fork the process. If successful, returns Ok((0, -1)) // in the child, and Ok((child_pid, -1)) in the parent. - #[cfg(not(any(target_os = "linux", all(target_os = "nto", target_env = "nto71"))))] + #[cfg(not(any( + target_os = "linux", + target_os = "watchos", + target_os = "tvos", + all(target_os = "nto", target_env = "nto71"), + )))] unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> { cvt(libc::fork()).map(|res| (res, -1)) } @@ -339,6 +367,7 @@ impl Command { // allocation). Instead we just close it manually. This will never // have the drop glue anyway because this code never returns (the // child will either exec() or invoke libc::exit) + #[cfg(not(any(target_os = "tvos", target_os = "watchos")))] unsafe fn do_exec( &mut self, stdio: ChildPipes, @@ -445,8 +474,19 @@ impl Command { Err(io::Error::last_os_error()) } + #[cfg(any(target_os = "tvos", target_os = "watchos"))] + unsafe fn do_exec( + &mut self, + _stdio: ChildPipes, + _maybe_envp: Option<&CStringArray>, + ) -> Result<!, io::Error> { + return Err(Self::ERR_APPLE_TV_WATCH_NO_FORK_EXEC); + } + #[cfg(not(any( target_os = "macos", + target_os = "tvos", + target_os = "watchos", target_os = "freebsd", all(target_os = "linux", target_env = "gnu"), all(target_os = "linux", target_env = "musl"), @@ -464,6 +504,9 @@ impl Command { // directly. #[cfg(any( target_os = "macos", + // FIXME: `target_os = "ios"`? + target_os = "tvos", + target_os = "watchos", target_os = "freebsd", all(target_os = "linux", target_env = "gnu"), all(target_os = "linux", target_env = "musl"), @@ -550,7 +593,7 @@ impl Command { } let addchdir = match self.get_cwd() { Some(cwd) => { - if cfg!(target_os = "macos") { + if cfg!(any(target_os = "macos", target_os = "tvos", target_os = "watchos")) { // There is a bug in macOS where a relative executable // path like "../myprogram" will cause `posix_spawn` to // successfully launch the program, but erroneously return diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs index d8b63546b9e..d471be33ed5 100644 --- a/library/std/src/sys/unix/rand.rs +++ b/library/std/src/sys/unix/rand.rs @@ -14,6 +14,7 @@ pub fn hashmap_random_keys() -> (u64, u64) { unix, not(target_os = "macos"), not(target_os = "ios"), + not(target_os = "tvos"), not(target_os = "watchos"), not(target_os = "openbsd"), not(target_os = "freebsd"), @@ -198,7 +199,7 @@ mod imp { // once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is // only used on iOS where direct access to `/dev/urandom` is blocked by the // sandbox. -#[cfg(any(target_os = "ios", target_os = "watchos"))] +#[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))] mod imp { use crate::io; use crate::ptr; diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 010015667f7..893f8b8df3f 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -150,7 +150,7 @@ impl Thread { } } - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] pub fn set_name(name: &CStr) { unsafe { let name = truncate_cstr::<{ libc::MAXTHREADNAMESIZE }>(name); @@ -283,7 +283,13 @@ impl Drop for Thread { } } -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[cfg(any( + target_os = "linux", + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", +))] fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] { let mut result = [0; MAX_WITH_NUL]; for (src, dst) in cstr.to_bytes().iter().zip(&mut result[..MAX_WITH_NUL - 1]) { @@ -299,6 +305,7 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> { target_os = "emscripten", target_os = "fuchsia", target_os = "ios", + target_os = "tvos", target_os = "linux", target_os = "macos", target_os = "solaris", diff --git a/library/std/src/sys/unix/thread_parking/pthread.rs b/library/std/src/sys/unix/thread_parking/pthread.rs index 8bf4bae7a3f..ae805d84399 100644 --- a/library/std/src/sys/unix/thread_parking/pthread.rs +++ b/library/std/src/sys/unix/thread_parking/pthread.rs @@ -46,6 +46,7 @@ unsafe fn wait_timeout( #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "espidf", target_os = "horizon", @@ -73,6 +74,7 @@ unsafe fn wait_timeout( #[cfg(not(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "espidf", target_os = "horizon", @@ -120,6 +122,7 @@ impl Parker { if #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "l4re", target_os = "android", diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index a9fbc7ab108..17b4130c202 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -219,7 +219,8 @@ impl From<__timespec64> for Timespec { #[cfg(any( all(target_os = "macos", any(not(target_arch = "aarch64"))), target_os = "ios", - target_os = "watchos" + target_os = "watchos", + target_os = "tvos" ))] mod inner { use crate::sync::atomic::{AtomicU64, Ordering}; @@ -339,7 +340,8 @@ mod inner { #[cfg(not(any( all(target_os = "macos", any(not(target_arch = "aarch64"))), target_os = "ios", - target_os = "watchos" + target_os = "watchos", + target_os = "tvos" )))] mod inner { use crate::fmt; diff --git a/library/std/src/sys/unix/weak.rs b/library/std/src/sys/unix/weak.rs index 62ffee70bec..61088ff16ed 100644 --- a/library/std/src/sys/unix/weak.rs +++ b/library/std/src/sys/unix/weak.rs @@ -28,7 +28,7 @@ use crate::ptr; use crate::sync::atomic::{self, AtomicPtr, Ordering}; // We can use true weak linkage on ELF targets. -#[cfg(not(any(target_os = "macos", target_os = "ios")))] +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "tvos")))] pub(crate) macro weak { (fn $name:ident($($t:ty),*) -> $ret:ty) => ( let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = { @@ -43,7 +43,7 @@ pub(crate) macro weak { } // On non-ELF targets, use the dlsym approximation of weak linkage. -#[cfg(any(target_os = "macos", target_os = "ios"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos"))] pub(crate) use self::dlsym as weak; pub(crate) struct ExternWeak<F: Copy> { diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index 2404bbe2b89..1ae42cb7eae 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -159,7 +159,7 @@ impl Socket { } let mut timeout = c::timeval { - tv_sec: timeout.as_secs() as c_long, + tv_sec: cmp::min(timeout.as_secs(), c_long::MAX as u64) as c_long, tv_usec: (timeout.subsec_nanos() / 1000) as c_long, }; diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 652c695fc57..2976a9f578e 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -18,7 +18,7 @@ use crate::ffi::{c_int, c_void}; cfg_if::cfg_if! { if #[cfg(any( target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", target_os = "macos", target_os = "watchos", + target_os = "ios", target_os = "tvos", target_os = "macos", target_os = "watchos", target_os = "openbsd", target_os = "netbsd", target_os = "illumos", target_os = "solaris", target_os = "haiku", target_os = "l4re", target_os = "nto"))] { use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 1230bb5deed..e4581c2de78 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -889,7 +889,7 @@ impl Drop for PanicGuard { /// it is guaranteed that this function will not panic (it may abort the /// process if the implementation encounters some rare errors). /// -/// # park and unpark +/// # `park` and `unpark` /// /// Every thread is equipped with some basic low-level blocking support, via the /// [`thread::park`][`park`] function and [`thread::Thread::unpark`][`unpark`] @@ -910,14 +910,6 @@ impl Drop for PanicGuard { /// if it wasn't already. Because the token is initially absent, [`unpark`] /// followed by [`park`] will result in the second call returning immediately. /// -/// In other words, each [`Thread`] acts a bit like a spinlock that can be -/// locked and unlocked using `park` and `unpark`. -/// -/// Notice that being unblocked does not imply any synchronization with someone -/// that unparked this thread, it could also be spurious. -/// For example, it would be a valid, but inefficient, implementation to make both [`park`] and -/// [`unpark`] return immediately without doing anything. -/// /// The API is typically used by acquiring a handle to the current thread, /// placing that handle in a shared data structure so that other threads can /// find it, and then `park`ing in a loop. When some desired condition is met, another @@ -931,6 +923,23 @@ impl Drop for PanicGuard { /// /// * It can be implemented very efficiently on many platforms. /// +/// # Memory Ordering +/// +/// Calls to `park` _synchronize-with_ calls to `unpark`, meaning that memory +/// operations performed before a call to `unpark` are made visible to the thread that +/// consumes the token and returns from `park`. Note that all `park` and `unpark` +/// operations for a given thread form a total order and `park` synchronizes-with +/// _all_ prior `unpark` operations. +/// +/// In atomic ordering terms, `unpark` performs a `Release` operation and `park` +/// performs the corresponding `Acquire` operation. Calls to `unpark` for the same +/// thread form a [release sequence]. +/// +/// Note that being unblocked does not imply a call was made to `unpark`, because +/// wakeups can also be spurious. For example, a valid, but inefficient, +/// implementation could have `park` and `unpark` return immediately without doing anything, +/// making *all* wakeups spurious. +/// /// # Examples /// /// ``` @@ -944,7 +953,7 @@ impl Drop for PanicGuard { /// let parked_thread = thread::spawn(move || { /// // We want to wait until the flag is set. We *could* just spin, but using /// // park/unpark is more efficient. -/// while !flag2.load(Ordering::Acquire) { +/// while !flag2.load(Ordering::Relaxed) { /// println!("Parking thread"); /// thread::park(); /// // We *could* get here spuriously, i.e., way before the 10ms below are over! @@ -961,7 +970,7 @@ impl Drop for PanicGuard { /// // There is no race condition here, if `unpark` /// // happens first, `park` will return immediately. /// // Hence there is no risk of a deadlock. -/// flag.store(true, Ordering::Release); +/// flag.store(true, Ordering::Relaxed); /// println!("Unpark the thread"); /// parked_thread.thread().unpark(); /// @@ -970,6 +979,7 @@ impl Drop for PanicGuard { /// /// [`unpark`]: Thread::unpark /// [`thread::park_timeout`]: park_timeout +/// [release sequence]: https://en.cppreference.com/w/cpp/atomic/memory_order#Release_sequence #[stable(feature = "rust1", since = "1.0.0")] pub fn park() { let guard = PanicGuard; diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index b65e2572cc5..5d6b9e94ee9 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -42,6 +42,7 @@ fn test_named_thread() { all(target_os = "linux", target_env = "gnu"), target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos" ))] #[test] diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index f6a68073b2f..ec24e137572 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -117,7 +117,7 @@ extern "C" { } cfg_if::cfg_if! { -if #[cfg(any(target_os = "ios", target_os = "watchos", target_os = "netbsd", not(target_arch = "arm")))] { +if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "netbsd", not(target_arch = "arm")))] { // Not ARM EHABI #[repr(C)] #[derive(Copy, Clone, PartialEq)] diff --git a/rustfmt.toml b/rustfmt.toml index 828d492a3d1..597ef5b9052 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -38,6 +38,5 @@ ignore = [ # these are ignored by a standard cargo fmt run "compiler/rustc_codegen_cranelift/y.rs", # running rustfmt breaks this file - "compiler/rustc_codegen_cranelift/example", "compiler/rustc_codegen_cranelift/scripts", ] diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 473fdbe1edc..5714613cdf5 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -620,7 +620,7 @@ class RustBuild(object): # The latter one does not exist on NixOS when using tmpfs as root. try: with open("/etc/os-release", "r") as f: - if not any(l.strip() in ("ID=nixos", "ID='nixos'", 'ID="nixos"') for l in f): + if not any(ln.strip() in ("ID=nixos", "ID='nixos'", 'ID="nixos"') for ln in f): return False except FileNotFoundError: return False @@ -872,7 +872,7 @@ class RustBuild(object): } for var_name, toml_key in var_data.items(): toml_val = self.get_toml(toml_key, build_section) - if toml_val != None: + if toml_val is not None: env["{}_{}".format(var_name, host_triple_sanitized)] = toml_val # preserve existing RUSTFLAGS diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 4481e1668b6..a16f77317c8 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -9,7 +9,7 @@ rust_dir = os.path.dirname(os.path.abspath(__file__)) rust_dir = os.path.dirname(rust_dir) rust_dir = os.path.dirname(rust_dir) sys.path.append(os.path.join(rust_dir, "src", "bootstrap")) -import bootstrap +import bootstrap # noqa: E402 class Option(object): @@ -319,7 +319,7 @@ def apply_args(known_args, option_checking, config): for key in known_args: # The `set` option is special and can be passed a bunch of times if key == 'set': - for option, value in known_args[key]: + for _option, value in known_args[key]: keyval = value.split('=', 1) if len(keyval) == 1 or keyval[1] == "true": value = True @@ -401,7 +401,7 @@ def parse_example_config(known_args, config): top_level_keys = [] for line in open(rust_dir + '/config.example.toml').read().split("\n"): - if cur_section == None: + if cur_section is None: if line.count('=') == 1: top_level_key = line.split('=')[0] top_level_key = top_level_key.strip(' #') @@ -523,8 +523,8 @@ def write_uncommented(target, f): block.append(line) if len(line) == 0: if not is_comment: - for l in block: - f.write(l + "\n") + for ln in block: + f.write(ln + "\n") block = [] is_comment = True continue diff --git a/src/bootstrap/download.rs b/src/bootstrap/download.rs index 06f479808b9..cb40521dda7 100644 --- a/src/bootstrap/download.rs +++ b/src/bootstrap/download.rs @@ -54,9 +54,9 @@ impl Config { /// Runs a command, printing out nice contextual information if it fails. /// Exits if the command failed to execute at all, otherwise returns its /// `status.success()`. - pub(crate) fn try_run(&self, cmd: &mut Command) -> bool { + pub(crate) fn try_run(&self, cmd: &mut Command) -> Result<(), ()> { if self.dry_run() { - return true; + return Ok(()); } self.verbose(&format!("running: {:?}", cmd)); try_run(cmd, self.is_verbose()) @@ -156,12 +156,14 @@ impl Config { ]; } "; - nix_build_succeeded = self.try_run(Command::new("nix-build").args(&[ - Path::new("-E"), - Path::new(NIX_EXPR), - Path::new("-o"), - &nix_deps_dir, - ])); + nix_build_succeeded = self + .try_run(Command::new("nix-build").args(&[ + Path::new("-E"), + Path::new(NIX_EXPR), + Path::new("-o"), + &nix_deps_dir, + ])) + .is_ok(); nix_deps_dir }); if !nix_build_succeeded { @@ -186,7 +188,7 @@ impl Config { patchelf.args(&["--set-interpreter", dynamic_linker.trim_end()]); } - self.try_run(patchelf.arg(fname)); + self.try_run(patchelf.arg(fname)).unwrap(); } fn download_file(&self, url: &str, dest_path: &Path, help_on_error: &str) { @@ -237,7 +239,7 @@ impl Config { "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')", url, tempfile.to_str().expect("invalid UTF-8 not supported with powershell downloads"), ), - ])) { + ])).is_err() { return; } eprintln!("\nspurious failure, trying again"); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index d7e77aeb338..d389b568f56 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -333,7 +333,7 @@ forward! { create(path: &Path, s: &str), remove(f: &Path), tempdir() -> PathBuf, - try_run(cmd: &mut Command) -> bool, + try_run(cmd: &mut Command) -> Result<(), ()>, llvm_link_shared() -> bool, download_rustc() -> bool, initial_rustfmt() -> Option<PathBuf>, @@ -614,11 +614,13 @@ impl Build { } // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error). - let has_local_modifications = !self.try_run( - Command::new("git") - .args(&["diff-index", "--quiet", "HEAD"]) - .current_dir(&absolute_path), - ); + let has_local_modifications = self + .try_run( + Command::new("git") + .args(&["diff-index", "--quiet", "HEAD"]) + .current_dir(&absolute_path), + ) + .is_err(); if has_local_modifications { self.run(Command::new("git").args(&["stash", "push"]).current_dir(&absolute_path)); } diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 779db9fffa8..9476137968b 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -60,18 +60,19 @@ prepare: ## MSVC native builders # this intentionally doesn't use `$(BOOTSTRAP)` so we can test the shebang on Windows -ci-msvc: - $(Q)$(CFG_SRC_DIR)/x.py test --stage 2 +ci-msvc-py: + $(Q)$(CFG_SRC_DIR)/x.py test --stage 2 tidy +ci-msvc-ps1: + $(Q)$(CFG_SRC_DIR)/x.ps1 test --stage 2 --exclude tidy +ci-msvc: ci-msvc-py ci-msvc-ps1 ## MingW native builders -TESTS_IN_MINGW_2 := \ - tests/ui - -ci-mingw-subset-1: - $(Q)$(CFG_SRC_DIR)/x test --stage 2 $(TESTS_IN_MINGW_2:%=--exclude %) -ci-mingw-subset-2: - $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_MINGW_2) - +# test both x and bootstrap entrypoints +ci-mingw-x: + $(Q)$(CFG_SRC_DIR)/x test --stage 2 tidy +ci-mingw-bootstrap: + $(Q)$(BOOTSTRAP) test --stage 2 --exclude tidy +ci-mingw: ci-mingw-x ci-mingw-bootstrap .PHONY: dist diff --git a/src/bootstrap/run.rs b/src/bootstrap/run.rs index ec01f744b82..c97b7592737 100644 --- a/src/bootstrap/run.rs +++ b/src/bootstrap/run.rs @@ -27,7 +27,8 @@ impl Step for ExpandYamlAnchors { try_run( builder, &mut builder.tool_cmd(Tool::ExpandYamlAnchors).arg("generate").arg(&builder.src), - ); + ) + .unwrap(); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -39,17 +40,17 @@ impl Step for ExpandYamlAnchors { } } -fn try_run(builder: &Builder<'_>, cmd: &mut Command) -> bool { +fn try_run(builder: &Builder<'_>, cmd: &mut Command) -> Result<(), ()> { if !builder.fail_fast { - if !builder.try_run(cmd) { + if let Err(e) = builder.try_run(cmd) { let mut failures = builder.delayed_failures.borrow_mut(); failures.push(format!("{:?}", cmd)); - return false; + return Err(e); } } else { builder.run(cmd); } - true + Ok(()) } #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index e13f3f0bd5e..7eb70de91f8 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -20,7 +20,7 @@ pub enum Profile { Codegen, Library, Tools, - Dist, + User, None, } @@ -43,7 +43,7 @@ impl Profile { pub fn all() -> impl Iterator<Item = Self> { use Profile::*; // N.B. these are ordered by how they are displayed, not alphabetically - [Library, Compiler, Codegen, Tools, Dist, None].iter().copied() + [Library, Compiler, Codegen, Tools, User, None].iter().copied() } pub fn purpose(&self) -> String { @@ -53,7 +53,7 @@ impl Profile { Compiler => "Contribute to the compiler itself", Codegen => "Contribute to the compiler, and also modify LLVM or codegen", Tools => "Contribute to tools which depend on the compiler, but do not modify it directly (e.g. rustdoc, clippy, miri)", - Dist => "Install Rust from source", + User => "Install Rust from source", None => "Do not modify `config.toml`" } .to_string() @@ -73,7 +73,7 @@ impl Profile { Profile::Codegen => "codegen", Profile::Library => "library", Profile::Tools => "tools", - Profile::Dist => "dist", + Profile::User => "user", Profile::None => "none", } } @@ -87,7 +87,7 @@ impl FromStr for Profile { "lib" | "library" => Ok(Profile::Library), "compiler" => Ok(Profile::Compiler), "llvm" | "codegen" => Ok(Profile::Codegen), - "maintainer" | "dist" => Ok(Profile::Dist), + "maintainer" | "user" => Ok(Profile::User), "tools" | "tool" | "rustdoc" | "clippy" | "miri" | "rustfmt" | "rls" => { Ok(Profile::Tools) } @@ -160,7 +160,7 @@ pub fn setup(config: &Config, profile: Profile) { "test src/tools/rustfmt", ], Profile::Library => &["check", "build", "test library/std", "doc"], - Profile::Dist => &["dist", "build"], + Profile::User => &["dist", "build"], }; println!(); @@ -170,7 +170,7 @@ pub fn setup(config: &Config, profile: Profile) { println!("- `x.py {}`", cmd); } - if profile != Profile::Dist { + if profile != Profile::User { println!( "For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html" ); diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 01d0dbafd1e..873ed61daf3 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -44,20 +44,21 @@ const MIR_OPT_BLESS_TARGET_MAPPING: &[(&str, &str)] = &[ ("i686-pc-windows-msvc", "x86_64-pc-windows-msvc"), ("i686-pc-windows-gnu", "x86_64-pc-windows-gnu"), ("i686-apple-darwin", "x86_64-apple-darwin"), - ("i686-apple-darwin", "aarch64-apple-darwin"), + // ARM Macs don't have a corresponding 32-bit target that they can (easily) + // build for, so there is no entry for "aarch64-apple-darwin" here. ]; -fn try_run(builder: &Builder<'_>, cmd: &mut Command) -> bool { +fn try_run(builder: &Builder<'_>, cmd: &mut Command) -> Result<(), ()> { if !builder.fail_fast { - if !builder.try_run(cmd) { + if let Err(e) = builder.try_run(cmd) { let mut failures = builder.delayed_failures.borrow_mut(); failures.push(format!("{:?}", cmd)); - return false; + return Err(e); } } else { builder.run(cmd); } - true + Ok(()) } fn try_run_quiet(builder: &Builder<'_>, cmd: &mut Command) -> bool { @@ -186,7 +187,8 @@ You can skip linkcheck with --exclude src/tools/linkchecker" try_run( builder, builder.tool_cmd(Tool::Linkchecker).arg(builder.out.join(host.triple).join("doc")), - ); + ) + .unwrap(); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -239,7 +241,8 @@ impl Step for HtmlCheck { builder.default_doc(&[]); builder.ensure(crate::doc::Rustc::new(builder.top_stage, self.target, builder)); - try_run(builder, builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target))); + try_run(builder, builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target))) + .unwrap(); } } @@ -285,7 +288,8 @@ impl Step for Cargotest { .args(builder.config.test_args()) .env("RUSTC", builder.rustc(compiler)) .env("RUSTDOC", builder.rustdoc(compiler)), - ); + ) + .unwrap(); } } @@ -784,7 +788,7 @@ impl Step for Clippy { cargo.add_rustc_lib_path(builder, compiler); let mut cargo = prepare_cargo_test(cargo, &[], &[], "clippy", compiler, host, builder); - if builder.try_run(&mut cargo) { + if builder.try_run(&mut cargo).is_ok() { // The tests succeeded; nothing to do. return; } @@ -857,7 +861,7 @@ impl Step for RustdocTheme { util::lld_flag_no_threads(self.compiler.host.contains("windows")), ); } - try_run(builder, &mut cmd); + try_run(builder, &mut cmd).unwrap(); } } @@ -1108,7 +1112,7 @@ help: to skip test's attempt to check tidiness, pass `--exclude src/tools/tidy` } builder.info("tidy check"); - try_run(builder, &mut cmd); + try_run(builder, &mut cmd).unwrap(); builder.ensure(ExpandYamlAnchors); @@ -1156,7 +1160,8 @@ impl Step for ExpandYamlAnchors { try_run( builder, &mut builder.tool_cmd(Tool::ExpandYamlAnchors).arg("check").arg(&builder.src), - ); + ) + .unwrap(); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -1935,7 +1940,7 @@ impl BookTest { compiler.host, ); let _time = util::timeit(&builder); - let toolstate = if try_run(builder, &mut rustbook_cmd) { + let toolstate = if try_run(builder, &mut rustbook_cmd).is_ok() { ToolState::TestPass } else { ToolState::TestFail @@ -2093,7 +2098,7 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> cmd.arg("--test-args").arg(test_args); if builder.config.verbose_tests { - try_run(builder, &mut cmd) + try_run(builder, &mut cmd).is_ok() } else { try_run_quiet(builder, &mut cmd) } @@ -2121,7 +2126,7 @@ impl Step for RustcGuide { let src = builder.src.join(relative_path); let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook); - let toolstate = if try_run(builder, rustbook_cmd.arg("linkcheck").arg(&src)) { + let toolstate = if try_run(builder, rustbook_cmd.arg("linkcheck").arg(&src)).is_ok() { ToolState::TestPass } else { ToolState::TestFail @@ -2660,7 +2665,7 @@ impl Step for Bootstrap { fn run(self, builder: &Builder<'_>) { let mut check_bootstrap = Command::new(&builder.python()); check_bootstrap.arg("bootstrap_test.py").current_dir(builder.src.join("src/bootstrap/")); - try_run(builder, &mut check_bootstrap); + try_run(builder, &mut check_bootstrap).unwrap(); let host = builder.config.build; let compiler = builder.compiler(0, host); @@ -2732,7 +2737,7 @@ impl Step for TierCheck { } builder.info("platform support check"); - try_run(builder, &mut cargo.into()); + try_run(builder, &mut cargo.into()).unwrap(); } } @@ -2812,7 +2817,7 @@ impl Step for RustInstaller { cmd.env("CARGO", &builder.initial_cargo); cmd.env("RUSTC", &builder.initial_rustc); cmd.env("TMP_DIR", &tmpdir); - try_run(builder, &mut cmd); + try_run(builder, &mut cmd).unwrap(); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 96341b69df0..126f0b1eb31 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -107,7 +107,7 @@ impl Step for ToolBuild { ); let mut cargo = Command::from(cargo); - let is_expected = builder.try_run(&mut cargo); + let is_expected = builder.try_run(&mut cargo).is_ok(); builder.save_toolstate( tool, diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 7e29f671f02..b291584b300 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -159,8 +159,6 @@ pub fn symlink_dir(config: &Config, original: &Path, link: &Path) -> io::Result< pub enum CiEnv { /// Not a CI environment. None, - /// The Azure Pipelines environment, for Linux (including Docker), Windows, and macOS builds. - AzurePipelines, /// The GitHub Actions environment, for Linux (including Docker), Windows and macOS builds. GitHubActions, } @@ -230,7 +228,7 @@ pub fn is_valid_test_suite_arg<'a, P: AsRef<Path>>( } pub fn run(cmd: &mut Command, print_cmd_on_fail: bool) { - if !try_run(cmd, print_cmd_on_fail) { + if try_run(cmd, print_cmd_on_fail).is_err() { crate::detail_exit_macro!(1); } } diff --git a/src/ci/cpu-usage-over-time.py b/src/ci/cpu-usage-over-time.py index adfd895ead0..adfd895ead0 100644..100755 --- a/src/ci/cpu-usage-over-time.py +++ b/src/ci/cpu-usage-over-time.py diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py index ffae7b0d4ac..ffae7b0d4ac 100644..100755 --- a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py +++ b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 2fe3438e0fe..0a098467d94 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -254,8 +254,6 @@ docker \ --env DEPLOY \ --env DEPLOY_ALT \ --env CI \ - --env TF_BUILD \ - --env BUILD_SOURCEBRANCHNAME \ --env GITHUB_ACTIONS \ --env GITHUB_REF \ --env TOOLSTATE_REPO_ACCESS_TOKEN \ diff --git a/src/ci/docker/scripts/android-sdk-manager.py b/src/ci/docker/scripts/android-sdk-manager.py index c9e2961f6eb..66cba58427b 100755 --- a/src/ci/docker/scripts/android-sdk-manager.py +++ b/src/ci/docker/scripts/android-sdk-manager.py @@ -2,6 +2,14 @@ # Simpler reimplementation of Android's sdkmanager # Extra features of this implementation are pinning and mirroring +import argparse +import hashlib +import os +import subprocess +import tempfile +import urllib.request +import xml.etree.ElementTree as ET + # These URLs are the Google repositories containing the list of available # packages and their versions. The list has been generated by listing the URLs # fetched while executing `tools/bin/sdkmanager --list` @@ -27,15 +35,6 @@ MIRROR_BUCKET = "rust-lang-ci-mirrors" MIRROR_BUCKET_REGION = "us-west-1" MIRROR_BASE_DIR = "rustc/android/" -import argparse -import hashlib -import os -import subprocess -import sys -import tempfile -import urllib.request -import xml.etree.ElementTree as ET - class Package: def __init__(self, path, url, sha1, deps=None): if deps is None: diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py index 73cf3de6a46..af01f9ccbbc 100755 --- a/src/ci/docker/scripts/fuchsia-test-runner.py +++ b/src/ci/docker/scripts/fuchsia-test-runner.py @@ -519,8 +519,8 @@ class TestEnvironment: env_vars += f'\n "{var_name}={var_value}",' # Default to no backtrace for test suite - if os.getenv("RUST_BACKTRACE") == None: - env_vars += f'\n "RUST_BACKTRACE=0",' + if os.getenv("RUST_BACKTRACE") is None: + env_vars += '\n "RUST_BACKTRACE=0",' # Use /tmp as the test temporary directory env_vars += f'\n "RUST_TEST_TMPDIR=/tmp",' diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index efffc382242..a9e42e4a0a0 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -639,41 +639,19 @@ jobs: # came from the mingw-w64 SourceForge download site. Unfortunately # SourceForge is notoriously flaky, so we mirror it on our own infrastructure. - - name: i686-mingw-1 + - name: i686-mingw env: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu - SCRIPT: make ci-mingw-subset-1 + SCRIPT: make ci-mingw # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 <<: *job-windows-8c - - name: i686-mingw-2 + - name: x86_64-mingw env: - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu - SCRIPT: make ci-mingw-subset-2 - # We are intentionally allowing an old toolchain on this builder (and that's - # incompatible with LLVM downloads today). - NO_DOWNLOAD_CI_LLVM: 1 - CUSTOM_MINGW: 1 - <<: *job-windows-8c - - - name: x86_64-mingw-1 - env: - SCRIPT: make ci-mingw-subset-1 - RUST_CONFIGURE_ARGS: >- - --build=x86_64-pc-windows-gnu - --enable-profiler - # We are intentionally allowing an old toolchain on this builder (and that's - # incompatible with LLVM downloads today). - NO_DOWNLOAD_CI_LLVM: 1 - CUSTOM_MINGW: 1 - <<: *job-windows-8c - - - name: x86_64-mingw-2 - env: - SCRIPT: make ci-mingw-subset-2 + SCRIPT: make ci-mingw RUST_CONFIGURE_ARGS: >- --build=x86_64-pc-windows-gnu --enable-profiler diff --git a/src/ci/github-actions/problem_matchers.json b/src/ci/github-actions/problem_matchers.json index 37561924b7d..b6c7ace841e 100644 --- a/src/ci/github-actions/problem_matchers.json +++ b/src/ci/github-actions/problem_matchers.json @@ -10,6 +10,46 @@ "message": 3 } ] + }, + { + "owner": "cargo-common", + "pattern": [ + { + "regexp": "^(warning|warn|error)(\\[(\\S*)\\])?: (.*)$", + "severity": 1, + "message": 4, + "code": 3 + }, + { + "regexp": "^\\s+-->\\s(\\S+):(\\d+):(\\d+)$", + "file": 1, + "line": 2, + "column": 3 + } + ] + }, + { + "owner": "compiler-panic", + "pattern": [ + { + "regexp": "error: internal compiler error: (.*):(\\d+):(\\d+): (.*)$", + "message": 4, + "file": 1, + "line": 2, + "column": 3 + } + ] + }, + { + "owner": "cargo-fmt", + "pattern": [ + { + "regexp": "^(Diff in (\\S+)) at line (\\d+):", + "message": 1, + "file": 2, + "line": 3 + } + ] } ] } diff --git a/src/ci/stage-build.py b/src/ci/stage-build.py index febc0492b94..3f30b69e8f4 100644..100755 --- a/src/ci/stage-build.py +++ b/src/ci/stage-build.py @@ -440,7 +440,7 @@ def retry_action(action, name: str, max_fails: int = 5): try: action() return - except: + except BaseException: # also catch ctrl+c/sysexit LOGGER.error(f"Action `{name}` has failed\n{traceback.format_exc()}") raise Exception(f"Action `{name}` has failed after {max_fails} attempts") @@ -818,7 +818,7 @@ def run_tests(pipeline: Pipeline): # Extract rustc, libstd, cargo and src archives to create the optimized sysroot rustc_dir = extract_dist_dir(f"rustc-nightly-{PGO_HOST}") / "rustc" libstd_dir = extract_dist_dir(f"rust-std-nightly-{PGO_HOST}") / f"rust-std-{PGO_HOST}" - cargo_dir = extract_dist_dir(f"cargo-nightly-{PGO_HOST}") / f"cargo" + cargo_dir = extract_dist_dir(f"cargo-nightly-{PGO_HOST}") / "cargo" extracted_src_dir = extract_dist_dir("rust-src-nightly") / "rust-src" # We need to manually copy libstd to the extracted rustc sysroot diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 2b0431a159b..1e17a90a842 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -16,6 +16,7 @@ - [Target Tier Policy](target-tier-policy.md) - [Template for Target-specific Documentation](platform-support/TEMPLATE.md) - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md) + - [\*-apple-tvos](platform-support/apple-tvos.md) - [\*-apple-watchos\*](platform-support/apple-watchos.md) - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md) - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index f69dcd5983d..62f628f8229 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -214,7 +214,7 @@ host tools. target | std | host | notes -------|:---:|:----:|------- `aarch64-apple-ios-macabi` | ? | | Apple Catalyst on ARM64 -`aarch64-apple-tvos` | * | | ARM64 tvOS +[`aarch64-apple-tvos`](platform-support/apple-tvos.md) | ? | | ARM64 tvOS [`aarch64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | ARM64 Apple WatchOS Simulator [`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ | | ARM64 SOLID with TOPPERS/ASP3 [`aarch64-nintendo-switch-freestanding`](platform-support/aarch64-nintendo-switch-freestanding.md) | * | | ARM64 Nintendo Switch, Horizon @@ -316,7 +316,7 @@ target | std | host | notes `thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode ARMv7a Linux with NEON, MUSL [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? | | WebAssembly `x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst on x86_64 -`x86_64-apple-tvos` | * | | x86 64-bit tvOS +[`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ? | | x86 64-bit tvOS [`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | x86 64-bit Apple WatchOS simulator [`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS | [`x86_64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | diff --git a/src/doc/rustc/src/platform-support/apple-tvos.md b/src/doc/rustc/src/platform-support/apple-tvos.md new file mode 100644 index 00000000000..d87fd1959b4 --- /dev/null +++ b/src/doc/rustc/src/platform-support/apple-tvos.md @@ -0,0 +1,85 @@ +# `*-apple-tvos` +- aarch64-apple-tvos +- x86_64-apple-tvos + +**Tier: 3** + +Apple tvOS targets: +- Apple tvOS on aarch64 +- Apple tvOS Simulator on x86_64 + +## Target maintainers + +* [@thomcc](https://github.com/thomcc) + +## Requirements + +These targets are cross-compiled. You will need appropriate versions of Xcode +and the SDKs for tvOS (`AppleTVOS.sdk`) and/or the tvOS Simulator +(`AppleTVSimulator.sdk`) to build a toolchain and target these platforms. + +The targets support most (see below) of the standard library including the +allocator to the best of my knowledge, however they are very new, not yet +well-tested, and it is possible that there are various bugs. + +In theory we support back to tvOS version 7.0, although the actual minimum +version you can target may be newer than this, for example due to the versions +of Xcode and your SDKs. + +As with the other Apple targets, `rustc` respects the common environment +variables used by Xcode to configure this, in this case +`TVOS_DEPLOYMENT_TARGET`. + +#### Incompletely supported library functionality + +As mentioned, "most" of the standard library is supported, which means that some portions +are known to be unsupported. The following APIs are currently known to have +missing or incomplete support: + +- `std::process::Command`'s API will return an error if it is configured in a + manner which cannot be performed using `posix_spawn` -- this is because the + more flexible `fork`/`exec`-based approach is prohibited on these platforms in + favor of `posix_spawn{,p}` (which still probably will get you rejected from + app stores, so is likely sideloading-only). A concrete set of cases where this + will occur is difficult to enumerate (and would quickly become stale), but in + some cases it may be worked around by tweaking the manner in which `Command` + is invoked. + +## Building the target + +The targets can be built by enabling them for a `rustc` build in `config.toml`, by adding, for example: + +```toml +[build] +build-stage = 1 +target = ["aarch64-apple-tvos", "x86_64-apple-tvos"] +``` + +It's possible that cargo under `-Zbuild-std` may also be used to target them. + +## Building Rust programs + +*Note: Building for this target requires the corresponding TVOS SDK, as provided by Xcode.* + +Rust programs can be built for these targets + +```text +$ rustc --target aarch64-apple-tvos your-code.rs +... +$ rustc --target x86_64-apple-tvos your-code.rs +``` + +## Testing + +There is no support for running the Rust or standard library testsuite on tvOS +or the simulators at the moment. Testing has mostly been done manually with +builds of static libraries called from Xcode or a simulator. + +It hopefully will be possible to improve this in the future. + +## Cross-compilation toolchains and C code + +This target can be cross-compiled from x86_64 or aarch64 macOS hosts. + +Other hosts are not supported for cross-compilation, but might work when also +providing the required Xcode SDK. diff --git a/src/doc/style-guide/src/README.md b/src/doc/style-guide/src/README.md index adb73a7eef6..75013bb3df9 100644 --- a/src/doc/style-guide/src/README.md +++ b/src/doc/style-guide/src/README.md @@ -16,9 +16,21 @@ Rust code has similar formatting, less mental effort is required to comprehend a new project, lowering the barrier to entry for new developers. Thus, there are productivity benefits to using a formatting tool (such as -rustfmt), and even larger benefits by using a community-consistent formatting, -typically by using a formatting tool's default settings. +`rustfmt`), and even larger benefits by using a community-consistent +formatting, typically by using a formatting tool's default settings. +## The default Rust style + +The Rust Style Guide defines the default Rust style, and *recommends* that +developers and tools follow the default Rust style. Tools such as `rustfmt` use +the style guide as a reference for the default style. Everything in this style +guide, whether or not it uses language such as "must" or the imperative mood +such as "insert a space ..." or "break the line after ...", refers to the +default style. + +This should not be interpreted as forbidding developers from following a +non-default style, or forbidding tools from adding any particular configuration +options. ## Formatting conventions @@ -28,8 +40,47 @@ typically by using a formatting tool's default settings. * Each level of indentation must be four spaces (that is, all indentation outside of string literals and comments must be a multiple of four). * The maximum width for a line is 100 characters. -* A tool should be configurable for all three of these variables. +* A tool may choose to make some of these configurable. + +#### Block indent + +Prefer block indent over visual indent: + +```rust +// Block indent +a_function_call( + foo, + bar, +); + +// Visual indent +a_function_call(foo, + bar); +``` +This makes for smaller diffs (e.g., if `a_function_call` is renamed in the above +example) and less rightward drift. + +### Trailing commas + +Lists should have a trailing comma when followed by a newline: + +```rust +function_call( + argument, + another_argument, +); + +let array = [ + element, + another_element, + yet_another_element, +]; +``` + +This makes moving code (e.g., by copy and paste) easier, and makes diffs +smaller, as appending or removing items does not require modifying another line +to add or remove a comma. ### Blank lines @@ -48,11 +99,7 @@ fn bar() {} fn baz() {} ``` -Formatting tools should make the bounds on blank lines configurable: there -should be separate minimum and maximum numbers of newlines between both -statements and (top-level) items (i.e., four options). As described above, the -defaults for both statements and items should be minimum: 1, maximum: 2. - +Formatting tools may wish to make the bounds on blank lines configurable. ### [Module-level items](items.md) ### [Statements](statements.md) diff --git a/src/doc/style-guide/src/SUMMARY.md b/src/doc/style-guide/src/SUMMARY.md index 004692fa6a2..59fe9fdc669 100644 --- a/src/doc/style-guide/src/SUMMARY.md +++ b/src/doc/style-guide/src/SUMMARY.md @@ -2,10 +2,10 @@ [Introduction](README.md) -- [Module-level items](items.md) +- [Items](items.md) - [Statements](statements.md) - [Expressions](expressions.md) -- [Types](types.md) -- [Non-formatting conventions](advice.md) +- [Types and Bounds](types.md) +- [Other style advice](advice.md) - [`Cargo.toml` conventions](cargo.md) -- [Principles used for deciding these guidelines](principles.md) +- [Guiding principles and rationale](principles.md) diff --git a/src/doc/style-guide/src/advice.md b/src/doc/style-guide/src/advice.md index ab4b92b0a24..9a617be509c 100644 --- a/src/doc/style-guide/src/advice.md +++ b/src/doc/style-guide/src/advice.md @@ -25,9 +25,9 @@ if y { * Local variables shall be `snake_case`, * Macro names shall be `snake_case`, * Constants (`const`s and immutable `static`s) shall be `SCREAMING_SNAKE_CASE`. - * When a name is forbidden because it is a reserved word (e.g., `crate`), use a - trailing underscore to make the name legal (e.g., `crate_`), or use raw - identifiers if possible. + * When a name is forbidden because it is a reserved word (such as `crate`), + either use a raw identifier (`r#crate`) or use a trailing underscore + (`crate_`). Don't misspell the word (`krate`). ### Modules diff --git a/src/doc/style-guide/src/cargo.md b/src/doc/style-guide/src/cargo.md index 13b96ca8c5e..d3b67ae4582 100644 --- a/src/doc/style-guide/src/cargo.md +++ b/src/doc/style-guide/src/cargo.md @@ -1,4 +1,4 @@ -# Cargo.toml conventions +# `Cargo.toml` conventions ## Formatting conventions @@ -25,16 +25,17 @@ not indent any key names; start all key names at the start of a line. Use multi-line strings (rather than newline escape sequences) for any string values that include multiple lines, such as the crate description. -For array values, such as a list of authors, put the entire list on the same +For array values, such as a list of features, put the entire list on the same line as the key, if it fits. Otherwise, use block indentation: put a newline after the opening square bracket, indent each item by one indentation level, put a comma after each item (including the last), and put the closing square bracket at the start of a line by itself after the last item. ```rust -authors = [ - "A Uthor <a.uthor@example.org>", - "Another Author <author@example.net>", +some_feature = [ + "another_feature", + "yet_another_feature", + "some_dependency?/some_feature", ] ``` @@ -54,11 +55,11 @@ version = "4.5.6" ## Metadata conventions -The authors list should consist of strings that each contain an author name -followed by an email address in angle brackets: `Full Name <email@address>`. -It should not contain bare email addresses, or names without email addresses. -(The authors list may also include a mailing list address without an associated -name.) +The authors list, if present, should consist of strings that each contain an +author name followed by an email address in angle brackets: `Full Name +<email@address>`. It should not contain bare email addresses, or names without +email addresses. (The authors list may also include a mailing list address +without an associated name.) The license field must contain a valid [SPDX expression](https://spdx.org/spdx-specification-21-web-version#h.jxpfx0ykyb60), diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md index 96f66c89c25..8271b42da4c 100644 --- a/src/doc/style-guide/src/expressions.md +++ b/src/doc/style-guide/src/expressions.md @@ -690,7 +690,7 @@ Where it is possible to use a block form on the right-hand side and avoid breaking the left-hand side, do that. E.g. ```rust - // Assuming the following line does done fit in the max width + // Assuming the following line does not fit in the max width a_very_long_pattern | another_pattern => ALongStructName { ... }, diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md index 2835975355f..1e0e60248bf 100644 --- a/src/doc/style-guide/src/items.md +++ b/src/doc/style-guide/src/items.md @@ -1,5 +1,10 @@ ## Items +Items consist of the set of things permitted at the top level of a module. +However, Rust also allows some items to appear within some other types of +items, such as within a function. The same formatting conventions apply whether +an item appears at module level or within another item. + `extern crate` statements must be first in a file. They must be ordered alphabetically. @@ -15,8 +20,8 @@ Tools should make the above ordering optional. ### Function definitions -In Rust, one finds functions by searching for `fn [function-name]`; It's -important that you style your code so that it's very searchable in this way. +In Rust, people often find functions by searching for `fn [function-name]`, so +the formatting of function definitions shold enable this. The proper ordering and spacing is: @@ -63,8 +68,9 @@ let y = (11, 22, 33); In the declaration, put each variant on its own line, block indented. -Format each variant accordingly as either a struct, tuple struct, or identifier, -which doesn't require special formatting (but without the `struct` keyword. +Format each variant accordingly as either a struct (but without the `struct` +keyword), a tuple struct, or an identifier (which doesn't require special +formatting): ```rust enum FooBar { @@ -139,7 +145,7 @@ union Foo { Put the whole struct on one line if possible. Types in the parentheses should be separated by a comma and space with no trailing comma. No spaces around the -parentheses or semi-colon: +parentheses or semicolon: ```rust pub struct Foo(String, u8); @@ -230,7 +236,7 @@ impl Bar `extern crate foo;` -Use spaces around keywords, no spaces around the semi-colon. +Use spaces around keywords, no spaces around the semicolon. ### Modules @@ -245,7 +251,7 @@ mod foo; ``` Use spaces around keywords and before the opening brace, no spaces around the -semi-colon. +semicolon. ### macro\_rules! @@ -478,8 +484,8 @@ foo::{ A *group* of imports is a set of imports on the same or sequential lines. One or more blank lines or other items (e.g., a function) separate groups of imports. -Within a group of imports, imports must be sorted ascii-betically. Groups of -imports must not be merged or re-ordered. +Within a group of imports, imports must be sorted ASCIIbetically (uppercase +before lowercase). Groups of imports must not be merged or re-ordered. E.g., input: @@ -505,13 +511,9 @@ use b; Because of `macro_use`, attributes must also start a new group and prevent re-ordering. -Note that tools which only have access to syntax (such as Rustfmt) cannot tell -which imports are from an external crate or the std lib, etc. - - #### Ordering list import -Names in a list import must be sorted ascii-betically, but with `self` and +Names in a list import must be sorted ASCIIbetically, but with `self` and `super` first, and groups and glob imports last. This applies recursively. For example, `a::*` comes before `b::a` but `a::b` comes before `a::*`. E.g., `use foo::bar::{a, b::c, b::d, b::d::{x, y, z}, b::{self, r, s}};`. diff --git a/src/doc/style-guide/src/principles.md b/src/doc/style-guide/src/principles.md index 2d203f264e6..d548693e39e 100644 --- a/src/doc/style-guide/src/principles.md +++ b/src/doc/style-guide/src/principles.md @@ -1,7 +1,7 @@ # Guiding principles and rationale -When deciding on style guidelines, the style team tried to be guided by the -following principles (in rough priority order): +When deciding on style guidelines, the style team follows these guiding +principles (in rough priority order): * readability - scan-ability @@ -19,35 +19,11 @@ following principles (in rough priority order): * specifics - compatibility with version control practices - preserving diffs, merge-friendliness, etc. - - preventing right-ward drift + - preventing rightward drift - minimising vertical space * application - ease of manual application - - ease of implementation (in Rustfmt, and in other tools/editors/code generators) + - ease of implementation (in `rustfmt`, and in other tools/editors/code generators) - internal consistency - simplicity of formatting rules - - -## Overarching guidelines - -Prefer block indent over visual indent. E.g., - -```rust -// Block indent -a_function_call( - foo, - bar, -); - -// Visual indent -a_function_call(foo, - bar); -``` - -This makes for smaller diffs (e.g., if `a_function_call` is renamed in the above -example) and less rightward drift. - -Lists should have a trailing comma when followed by a newline, see the block -indent example above. This choice makes moving code (e.g., by copy and paste) -easier and makes smaller diffs. diff --git a/src/doc/style-guide/src/statements.md b/src/doc/style-guide/src/statements.md index 671e6d31a57..62a5a032f07 100644 --- a/src/doc/style-guide/src/statements.md +++ b/src/doc/style-guide/src/statements.md @@ -1,7 +1,9 @@ +## Statements + ### Let statements There should be spaces after the `:` and on both sides of the `=` (if they are -present). No space before the semi-colon. +present). No space before the semicolon. ```rust // A comment. @@ -194,7 +196,7 @@ used to determine whether a let-else statement is *short*. ### Macros in statement position A macro use in statement position should use parentheses or square brackets as -delimiters and should be terminated with a semi-colon. There should be no spaces +delimiters and should be terminated with a semicolon. There should be no spaces between the name, `!`, the delimiters, or the `;`. ```rust @@ -205,13 +207,13 @@ a_macro!(...); ### Expressions in statement position -There should be no space between the expression and the semi-colon. +There should be no space between the expression and the semicolon. ``` <expr>; ``` -All expressions in statement position should be terminated with a semi-colon, +All expressions in statement position should be terminated with a semicolon, unless they end with a block or are used as the value for a block. E.g., @@ -229,7 +231,7 @@ loop { } ``` -Use a semi-colon where an expression has void type, even if it could be +Use a semicolon where an expression has void type, even if it could be propagated. E.g., ```rust diff --git a/src/etc/dec2flt_table.py b/src/etc/dec2flt_table.py index aa5188d96c3..9264a8439bb 100644..100755 --- a/src/etc/dec2flt_table.py +++ b/src/etc/dec2flt_table.py @@ -14,8 +14,7 @@ Adapted from Daniel Lemire's fast_float ``table_generation.py``, available here: <https://github.com/fastfloat/fast_float/blob/main/script/table_generation.py>. """ from __future__ import print_function -from math import ceil, floor, log, log2 -from fractions import Fraction +from math import ceil, floor, log from collections import deque HEADER = """ @@ -97,7 +96,6 @@ def print_proper_powers(min_exp, max_exp, bias): print('#[rustfmt::skip]') typ = '[(u64, u64); N_POWERS_OF_FIVE]' print('pub static POWER_OF_FIVE_128: {} = ['.format(typ)) - lo_mask = (1 << 64) - 1 for c, exp in powers: hi = '0x{:x}'.format(c // (1 << 64)) lo = '0x{:x}'.format(c % (1 << 64)) diff --git a/src/etc/gdb_load_rust_pretty_printers.py b/src/etc/gdb_load_rust_pretty_printers.py index 491b6ba9e9e..e05039ce474 100644 --- a/src/etc/gdb_load_rust_pretty_printers.py +++ b/src/etc/gdb_load_rust_pretty_printers.py @@ -4,6 +4,7 @@ from os import path self_dir = path.dirname(path.realpath(__file__)) sys.path.append(self_dir) +# ruff: noqa: E402 import gdb import gdb_lookup diff --git a/src/etc/generate-deriving-span-tests.py b/src/etc/generate-deriving-span-tests.py index d38f5add747..d61693460bc 100755 --- a/src/etc/generate-deriving-span-tests.py +++ b/src/etc/generate-deriving-span-tests.py @@ -102,7 +102,9 @@ for (trait, supers, errs) in [('Clone', [], 1), traits[trait] = (ALL, supers, errs) for (trait, (types, super_traits, error_count)) in traits.items(): - mk = lambda ty: create_test_case(ty, trait, super_traits, error_count) + def mk(ty, t=trait, st=super_traits, ec=error_count): + return create_test_case(ty, t, st, ec) + if types & ENUM: write_file(trait + '-enum', mk(ENUM_TUPLE)) write_file(trait + '-enum-struct-variant', mk(ENUM_STRUCT)) diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py index c97fb4b8054..5ab1874e9ed 100644..100755 --- a/src/etc/htmldocck.py +++ b/src/etc/htmldocck.py @@ -110,6 +110,9 @@ There are a number of supported commands: * `@has-dir PATH` checks for the existence of the given directory. +* `@files FOLDER_PATH [ENTRIES]`, checks that `FOLDER_PATH` contains exactly + `[ENTRIES]`. + All conditions can be negated with `!`. `@!has foo/type.NoSuch.html` checks if the given file does not exist, for example. @@ -144,7 +147,7 @@ VOID_ELEMENTS = {'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'ke # Python 2 -> 3 compatibility try: - unichr + unichr # noqa: B018 FIXME: py2 except NameError: unichr = chr @@ -321,12 +324,15 @@ class CachedFiles(object): else: return self.last_path + def get_absolute_path(self, path): + return os.path.join(self.root, path) + def get_file(self, path): path = self.resolve_path(path) if path in self.files: return self.files[path] - abspath = os.path.join(self.root, path) + abspath = self.get_absolute_path(path) if not(os.path.exists(abspath) and os.path.isfile(abspath)): raise FailedCheck('File does not exist {!r}'.format(path)) @@ -340,7 +346,7 @@ class CachedFiles(object): if path in self.trees: return self.trees[path] - abspath = os.path.join(self.root, path) + abspath = self.get_absolute_path(path) if not(os.path.exists(abspath) and os.path.isfile(abspath)): raise FailedCheck('File does not exist {!r}'.format(path)) @@ -348,13 +354,15 @@ class CachedFiles(object): try: tree = ET.fromstringlist(f.readlines(), CustomHTMLParser()) except Exception as e: - raise RuntimeError('Cannot parse an HTML file {!r}: {}'.format(path, e)) + raise RuntimeError( # noqa: B904 FIXME: py2 + 'Cannot parse an HTML file {!r}: {}'.format(path, e) + ) self.trees[path] = tree return self.trees[path] def get_dir(self, path): path = self.resolve_path(path) - abspath = os.path.join(self.root, path) + abspath = self.get_absolute_path(path) if not(os.path.exists(abspath) and os.path.isdir(abspath)): raise FailedCheck('Directory does not exist {!r}'.format(path)) @@ -422,7 +430,7 @@ def check_snapshot(snapshot_name, actual_tree, normalize_to_text): if bless: expected_str = None else: - raise FailedCheck('No saved snapshot value') + raise FailedCheck('No saved snapshot value') # noqa: B904 FIXME: py2 if not normalize_to_text: actual_str = ET.tostring(actual_tree).decode('utf-8') @@ -536,6 +544,41 @@ def get_nb_matching_elements(cache, c, regexp, stop_at_first): return check_tree_text(cache.get_tree(c.args[0]), pat, c.args[2], regexp, stop_at_first) +def check_files_in_folder(c, cache, folder, files): + files = files.strip() + if not files.startswith('[') or not files.endswith(']'): + raise InvalidCheck("Expected list as second argument of @{} (ie '[]')".format(c.cmd)) + + folder = cache.get_absolute_path(folder) + + # First we create a set of files to check if there are duplicates. + files = shlex.split(files[1:-1].replace(",", "")) + files_set = set() + for file in files: + if file in files_set: + raise InvalidCheck("Duplicated file `{}` in @{}".format(file, c.cmd)) + files_set.add(file) + folder_set = set([f for f in os.listdir(folder) if f != "." and f != ".."]) + + # Then we remove entries from both sets (we clone `folder_set` so we can iterate it while + # removing its elements). + for entry in set(folder_set): + if entry in files_set: + files_set.remove(entry) + folder_set.remove(entry) + + error = 0 + if len(files_set) != 0: + print_err(c.lineno, c.context, "Entries not found in folder `{}`: `{}`".format( + folder, files_set)) + error += 1 + if len(folder_set) != 0: + print_err(c.lineno, c.context, "Extra entries in folder `{}`: `{}`".format( + folder, folder_set)) + error += 1 + return error == 0 + + ERR_COUNT = 0 @@ -564,6 +607,13 @@ def check_command(c, cache): else: raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd)) + elif c.cmd == 'files': # check files in given folder + if len(c.args) != 2: # @files <folder path> <file list> + raise InvalidCheck("Invalid number of @{} arguments".format(c.cmd)) + elif c.negated: + raise InvalidCheck("@{} doesn't support negative check".format(c.cmd)) + ret = check_files_in_folder(c, cache, c.args[0], c.args[1]) + elif c.cmd == 'count': # count test if len(c.args) == 3: # @count <path> <pat> <count> = count test expected = int(c.args[2]) diff --git a/src/etc/lldb_batchmode.py b/src/etc/lldb_batchmode.py index fc355c87b52..db1e0035ea0 100644 --- a/src/etc/lldb_batchmode.py +++ b/src/etc/lldb_batchmode.py @@ -124,7 +124,7 @@ def start_breakpoint_listener(target): breakpoint = lldb.SBBreakpoint.GetBreakpointFromEvent(event) print_debug("breakpoint added, id = " + str(breakpoint.id)) new_breakpoints.append(breakpoint.id) - except: + except BaseException: # explicitly catch ctrl+c/sysexit print_debug("breakpoint listener shutting down") # Start the listener and let it run as a daemon diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index c4381e202b9..4c86b214646 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -1,6 +1,6 @@ import sys -from lldb import SBValue, SBData, SBError, eBasicTypeLong, eBasicTypeUnsignedLong, \ +from lldb import SBData, SBError, eBasicTypeLong, eBasicTypeUnsignedLong, \ eBasicTypeUnsignedChar # from lldb.formatters import Logger diff --git a/src/etc/test-float-parse/runtests.py b/src/etc/test-float-parse/runtests.py index cf7279534dc..cf7279534dc 100644..100755 --- a/src/etc/test-float-parse/runtests.py +++ b/src/etc/test-float-parse/runtests.py diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index c8a40e01501..492b0b79557 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -321,10 +321,10 @@ where let bound_predicate = pred.kind(); let tcx = self.cx.tcx; let regions = match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(poly_trait_pred)) => { tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_trait_pred)) } - ty::PredicateKind::Clause(ty::Clause::Projection(poly_proj_pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(poly_proj_pred)) => { tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_proj_pred)) } _ => return FxHashSet::default(), @@ -449,7 +449,7 @@ where .filter(|p| { !orig_bounds.contains(p) || match p.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { pred.def_id() == sized_trait } _ => false, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 29c11e1f335..f86c32158e0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -54,7 +54,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< let mut inserted = FxHashSet::default(); items.extend(doc.foreigns.iter().map(|(item, renamed)| { let item = clean_maybe_renamed_foreign_item(cx, item, *renamed); - if let Some(name) = item.name && !item.attrs.lists(sym::doc).has_word(sym::hidden) { + if let Some(name) = item.name && !item.is_doc_hidden() { inserted.insert((item.type_(), name)); } item @@ -64,7 +64,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< return None; } let item = clean_doc_module(x, cx); - if item.attrs.lists(sym::doc).has_word(sym::hidden) { + if item.is_doc_hidden() { // Hidden modules are stripped at a later stage. // If a hidden module has the same name as a visible one, we want // to keep both of them around. @@ -85,7 +85,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< } let v = clean_maybe_renamed_item(cx, item, *renamed, *import_id); for item in &v { - if let Some(name) = item.name && !item.attrs.lists(sym::doc).has_word(sym::hidden) { + if let Some(name) = item.name && !item.is_doc_hidden() { inserted.insert((item.type_(), name)); } } @@ -331,22 +331,22 @@ pub(crate) fn clean_predicate<'tcx>( ) -> Option<WherePredicate> { let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { clean_poly_trait_predicate(bound_predicate.rebind(pred), cx) } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(pred)) => { clean_region_outlives_predicate(pred) } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(pred)) => { clean_type_outlives_predicate(bound_predicate.rebind(pred), cx) } - ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { Some(clean_projection_predicate(bound_predicate.rebind(pred), cx)) } // FIXME(generic_const_exprs): should this do something? - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) => None, - ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) => None, - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None, + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) => None, + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) => None, + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => None, ty::PredicateKind::Subtype(..) | ty::PredicateKind::AliasRelate(..) @@ -805,20 +805,19 @@ fn clean_ty_generics<'tcx>( let param_idx = (|| { let bound_p = p.kind(); match bound_p.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { if let ty::Param(param) = pred.self_ty().kind() { return Some(param.index); } } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( - ty, - _reg, - ))) => { + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives( + ty::OutlivesPredicate(ty, _reg), + )) => { if let ty::Param(param) = ty.kind() { return Some(param.index); } } - ty::PredicateKind::Clause(ty::Clause::Projection(p)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => { if let ty::Param(param) = p.projection_ty.self_ty().kind() { projection = Some(bound_p.rebind(p)); return Some(param.index); @@ -1362,8 +1361,10 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( } if let ty::TraitContainer = assoc_item.container { - let bounds = - tcx.explicit_item_bounds(assoc_item.def_id).subst_identity_iter_copied(); + let bounds = tcx + .explicit_item_bounds(assoc_item.def_id) + .subst_identity_iter_copied() + .map(|(c, s)| (c.as_predicate(), s)); let predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates; let predicates = tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied())); @@ -2024,8 +2025,8 @@ pub(crate) fn clean_middle_ty<'tcx>( Tuple(t.iter().map(|t| clean_middle_ty(bound_ty.rebind(t), cx, None, None)).collect()) } - ty::Alias(ty::Projection, ref data) => { - clean_projection(bound_ty.rebind(*data), cx, parent_def_id) + ty::Alias(ty::Projection, data) => { + clean_projection(bound_ty.rebind(data), cx, parent_def_id) } ty::Alias(ty::Inherent, alias_ty) => { @@ -2053,8 +2054,21 @@ pub(crate) fn clean_middle_ty<'tcx>( } ty::Alias(ty::Weak, data) => { - let ty = cx.tcx.type_of(data.def_id).subst(cx.tcx, data.substs); - clean_middle_ty(bound_ty.rebind(ty), cx, None, None) + if cx.tcx.features().lazy_type_alias { + // Weak type alias `data` represents the `type X` in `type X = Y`. If we need `Y`, + // we need to use `type_of`. + let path = external_path( + cx, + data.def_id, + false, + ThinVec::new(), + bound_ty.rebind(data.substs), + ); + Type::Path { path } + } else { + let ty = cx.tcx.type_of(data.def_id).subst(cx.tcx, data.substs); + clean_middle_ty(bound_ty.rebind(ty), cx, None, None) + } } ty::Param(ref p) => { @@ -2105,7 +2119,7 @@ pub(crate) fn clean_middle_ty<'tcx>( fn clean_middle_opaque_bounds<'tcx>( cx: &mut DocContext<'tcx>, - bounds: Vec<ty::Predicate<'tcx>>, + bounds: Vec<ty::Clause<'tcx>>, ) -> Type { let mut regions = vec![]; let mut has_sized = false; @@ -2114,13 +2128,8 @@ fn clean_middle_opaque_bounds<'tcx>( .filter_map(|bound| { let bound_predicate = bound.kind(); let trait_ref = match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(tr)) => { - bound_predicate.rebind(tr.trait_ref) - } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( - _ty, - reg, - ))) => { + ty::ClauseKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref), + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => { if let Some(r) = clean_middle_region(reg) { regions.push(GenericBound::Outlives(r)); } @@ -2137,9 +2146,7 @@ fn clean_middle_opaque_bounds<'tcx>( let bindings: ThinVec<_> = bounds .iter() .filter_map(|bound| { - if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = - bound.kind().skip_binder() - { + if let ty::ClauseKind::Projection(proj) = bound.kind().skip_binder() { if proj.projection_ty.trait_ref(cx.tcx) == trait_ref.skip_binder() { Some(TypeBinding { assoc: projection_to_path_segment( diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 3c72b0bf9f2..a8221cc9449 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -128,7 +128,9 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId) .predicates .iter() .filter_map(|(pred, _)| { - if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred.kind().skip_binder() { + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = + pred.kind().skip_binder() + { if pred.trait_ref.self_ty() == self_ty { Some(pred.def_id()) } else { None } } else { None diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 1999a6b671d..5f5cade67a2 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -358,15 +358,15 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool { impl Item { pub(crate) fn stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<Stability> { - self.item_id.as_def_id().and_then(|did| tcx.lookup_stability(did)) + self.def_id().and_then(|did| tcx.lookup_stability(did)) } pub(crate) fn const_stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<ConstStability> { - self.item_id.as_def_id().and_then(|did| tcx.lookup_const_stability(did)) + self.def_id().and_then(|did| tcx.lookup_const_stability(did)) } pub(crate) fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> { - self.item_id.as_def_id().and_then(|did| tcx.lookup_deprecation(did)) + self.def_id().and_then(|did| tcx.lookup_deprecation(did)) } pub(crate) fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool { @@ -391,7 +391,7 @@ impl Item { panic!("blanket impl item has non-blanket ID") } } - _ => self.item_id.as_def_id().map(|did| rustc_span(did, tcx)), + _ => self.def_id().map(|did| rustc_span(did, tcx)), } } @@ -501,7 +501,7 @@ impl Item { } pub(crate) fn is_crate(&self) -> bool { - self.is_mod() && self.item_id.as_def_id().map_or(false, |did| did.is_crate_root()) + self.is_mod() && self.def_id().map_or(false, |did| did.is_crate_root()) } pub(crate) fn is_mod(&self) -> bool { self.type_() == ItemType::Module @@ -638,11 +638,11 @@ impl Item { } let header = match *self.kind { ItemKind::ForeignFunctionItem(_) => { - let def_id = self.item_id.as_def_id().unwrap(); + let def_id = self.def_id().unwrap(); let abi = tcx.fn_sig(def_id).skip_binder().abi(); hir::FnHeader { unsafety: if abi == Abi::RustIntrinsic { - intrinsic_operation_unsafety(tcx, self.item_id.as_def_id().unwrap()) + intrinsic_operation_unsafety(tcx, self.def_id().unwrap()) } else { hir::Unsafety::Unsafe }, @@ -659,7 +659,7 @@ impl Item { } } ItemKind::FunctionItem(_) | ItemKind::MethodItem(_, _) | ItemKind::TyMethodItem(_) => { - let def_id = self.item_id.as_def_id().unwrap(); + let def_id = self.def_id().unwrap(); build_fn_header(def_id, tcx, tcx.asyncness(def_id)) } _ => return None, @@ -738,7 +738,7 @@ impl Item { } }) .collect(); - if let Some(def_id) = self.item_id.as_def_id() && + if let Some(def_id) = self.def_id() && !def_id.is_local() && // This check is needed because `adt_def` will panic if not a compatible type otherwise... matches!(self.type_(), ItemType::Struct | ItemType::Enum | ItemType::Union) @@ -783,6 +783,14 @@ impl Item { } attrs } + + pub fn is_doc_hidden(&self) -> bool { + self.attrs.is_doc_hidden() + } + + pub fn def_id(&self) -> Option<DefId> { + self.item_id.as_def_id() + } } #[derive(Clone, Debug)] @@ -1129,6 +1137,10 @@ impl Attributes { false } + fn is_doc_hidden(&self) -> bool { + self.has_doc_flag(sym::hidden) + } + pub(crate) fn from_ast(attrs: &[ast::Attribute]) -> Attributes { Attributes::from_ast_iter(attrs.iter().map(|attr| (attr, None)), false) } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 294de12cea8..f375f0efbd1 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -21,6 +21,7 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_span::symbol::{kw, sym, Symbol}; use std::fmt::Write as _; use std::mem; +use std::sync::LazyLock as Lazy; use thin_vec::{thin_vec, ThinVec}; #[cfg(test)] @@ -582,6 +583,8 @@ pub(crate) fn has_doc_flag(tcx: TyCtxt<'_>, did: DefId, flag: Symbol) -> bool { /// /// Set by `bootstrap::Builder::doc_rust_lang_org_channel` in order to keep tests passing on beta/stable. pub(crate) const DOC_RUST_LANG_ORG_CHANNEL: &str = env!("DOC_RUST_LANG_ORG_CHANNEL"); +pub(crate) static DOC_CHANNEL: Lazy<&'static str> = + Lazy::new(|| DOC_RUST_LANG_ORG_CHANNEL.rsplit("/").filter(|c| !c.is_empty()).next().unwrap()); /// Render a sequence of macro arms in a format suitable for displaying to the user /// as part of an item declaration. diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 8aaad8bce1b..dac762e9ff9 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -121,6 +121,11 @@ pub(crate) struct Cache { pub(crate) intra_doc_links: FxHashMap<ItemId, FxIndexSet<clean::ItemLink>>, /// Cfg that have been hidden via #![doc(cfg_hide(...))] pub(crate) hidden_cfg: FxHashSet<clean::cfg::Cfg>, + + /// Contains the list of `DefId`s which have been inlined. It is used when generating files + /// to check if a stripped item should get its file generated or not: if it's inside a + /// `#[doc(hidden)]` item or a private one and not inlined, it shouldn't get a file. + pub(crate) inlined_items: DefIdSet, } /// This struct is used to wrap the `cache` and `tcx` in order to run `DocFolder`. diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index f26d74629dd..b710311c858 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -347,13 +347,19 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( } } else { let mut br_with_padding = String::with_capacity(6 * indent + 28); - br_with_padding.push_str("\n"); + br_with_padding.push('\n'); - let padding_amount = - if ending == Ending::Newline { indent + 4 } else { indent + "fn where ".len() }; + let where_indent = 3; + let padding_amount = if ending == Ending::Newline { + indent + 4 + } else if indent == 0 { + 4 + } else { + indent + where_indent + "where ".len() + }; for _ in 0..padding_amount { - br_with_padding.push_str(" "); + br_with_padding.push(' '); } let where_preds = where_preds.to_string().replace('\n', &br_with_padding); @@ -370,7 +376,8 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( let where_preds = where_preds.replacen(&br_with_padding, " ", 1); let mut clause = br_with_padding; - clause.truncate(clause.len() - "where ".len()); + // +1 is for `\n`. + clause.truncate(indent + 1 + where_indent); write!(clause, "<span class=\"where\">where{where_preds}</span>")?; clause diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 6ab849c92a0..8c5871d9126 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -55,6 +55,7 @@ struct PageLayout<'a> { sidebar: String, content: String, krate_with_trailing_slash: String, + rust_channel: &'static str, pub(crate) rustdoc_version: &'a str, } @@ -82,6 +83,7 @@ pub(crate) fn render<T: Print, S: Print>( sidebar, content, krate_with_trailing_slash, + rust_channel: *crate::clean::utils::DOC_CHANNEL, rustdoc_version, } .render() diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 56af257fd5e..4c476263635 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -73,6 +73,8 @@ pub(crate) struct Context<'tcx> { pub(crate) include_sources: bool, /// Collection of all types with notable traits referenced in the current module. pub(crate) types_with_notable_traits: FxHashSet<clean::Type>, + /// Field used during rendering, to know if we're inside an inlined item. + pub(crate) is_inside_inlined_module: bool, } // `Context` is cloned a lot, so we don't want the size to grow unexpectedly. @@ -171,6 +173,19 @@ impl<'tcx> Context<'tcx> { } fn render_item(&mut self, it: &clean::Item, is_module: bool) -> String { + let mut render_redirect_pages = self.render_redirect_pages; + // If the item is stripped but inlined, links won't point to the item so no need to generate + // a file for it. + if it.is_stripped() && + let Some(def_id) = it.def_id() && + def_id.is_local() + { + if self.is_inside_inlined_module || self.shared.cache.inlined_items.contains(&def_id) { + // For now we're forced to generate a redirect page for stripped items until + // `record_extern_fqn` correctly points to external items. + render_redirect_pages = true; + } + } let mut title = String::new(); if !is_module { title.push_str(it.name.unwrap().as_str()); @@ -205,7 +220,7 @@ impl<'tcx> Context<'tcx> { tyname.as_str() }; - if !self.render_redirect_pages { + if !render_redirect_pages { let clone_shared = Rc::clone(&self.shared); let page = layout::Page { css_class: tyname_s, @@ -545,6 +560,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { shared: Rc::new(scx), include_sources, types_with_notable_traits: FxHashSet::default(), + is_inside_inlined_module: false, }; if emit_crate { @@ -574,6 +590,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { shared: Rc::clone(&self.shared), include_sources: self.include_sources, types_with_notable_traits: FxHashSet::default(), + is_inside_inlined_module: self.is_inside_inlined_module, } } @@ -768,12 +785,22 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { info!("Recursing into {}", self.dst.display()); - let buf = self.render_item(item, true); - // buf will be empty if the module is stripped and there is no redirect for it - if !buf.is_empty() { - self.shared.ensure_dir(&self.dst)?; - let joint_dst = self.dst.join("index.html"); - self.shared.fs.write(joint_dst, buf)?; + if !item.is_stripped() { + let buf = self.render_item(item, true); + // buf will be empty if the module is stripped and there is no redirect for it + if !buf.is_empty() { + self.shared.ensure_dir(&self.dst)?; + let joint_dst = self.dst.join("index.html"); + self.shared.fs.write(joint_dst, buf)?; + } + } + if !self.is_inside_inlined_module { + if let Some(def_id) = item.def_id() && self.cache().inlined_items.contains(&def_id) { + self.is_inside_inlined_module = true; + } + } else if item.is_doc_hidden() { + // We're not inside an inlined module anymore since this one cannot be re-exported. + self.is_inside_inlined_module = false; } // Render sidebar-items.js used throughout this module. diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 322ab7a4af3..f923f905451 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -421,11 +421,10 @@ fn document<'a, 'cx: 'a>( display_fn(move |f| { document_item_info(cx, item, parent).render_into(f).unwrap(); if parent.is_none() { - write!(f, "{}", document_full_collapsible(item, cx, heading_offset))?; + write!(f, "{}", document_full_collapsible(item, cx, heading_offset)) } else { - write!(f, "{}", document_full(item, cx, heading_offset))?; + write!(f, "{}", document_full(item, cx, heading_offset)) } - Ok(()) }) } @@ -861,8 +860,8 @@ fn assoc_method( w.reserve(header_len + "<a href=\"\" class=\"fn\">{".len() + "</a>".len()); write!( w, - "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn <a{href} class=\"fn\">{name}</a>\ - {generics}{decl}{notable_traits}{where_clause}", + "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn \ + <a{href} class=\"fn\">{name}</a>{generics}{decl}{notable_traits}{where_clause}", indent = indent_str, vis = vis, constness = constness, diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index b487cfa5c25..21c1eb631e0 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -890,6 +890,10 @@ so that we can apply CSS-filters to change the arrow color in themes */ .search-results .result-name .grey { color: var(--search-results-grey-color); } +.search-results .result-name .typename { + color: var(--search-results-grey-color); + font-size: 0.875rem; +} .popover { position: absolute; diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index f5296abaee6..254b0d8bf5a 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1050,9 +1050,10 @@ function preLoadCss(cssUrl) { function buildHelpMenu() { const book_info = document.createElement("span"); + const channel = getVar("channel"); book_info.className = "top"; - book_info.innerHTML = "You can find more information in \ - <a href=\"https://doc.rust-lang.org/rustdoc/\">the rustdoc book</a>."; + book_info.innerHTML = `You can find more information in \ +<a href="https://doc.rust-lang.org/${channel}/rustdoc/">the rustdoc book</a>.`; const shortcuts = [ ["?", "Show this help dialog"], @@ -1072,6 +1073,9 @@ function preLoadCss(cssUrl) { div_shortcuts.innerHTML = "<h2>Keyboard Shortcuts</h2><dl>" + shortcuts + "</dl></div>"; const infos = [ + `For a full list of all search features, take a look <a \ +href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\ +#the-search-interface">here</a>.`, "Prefix searches with a type followed by a colon (e.g., <code>fn:</code>) to \ restrict the search to a given item kind.", "Accepted kinds are: <code>fn</code>, <code>mod</code>, <code>struct</code>, \ diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 3059dac8207..452348dc865 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2024,7 +2024,9 @@ function initSearch(rawSearchIndex) { resultName.insertAdjacentHTML( "beforeend", - `${typeName} ${item.displayPath}<span class="${type}">${name}</span>`); + `<span class="typename">${typeName}</span>` + + ` ${item.displayPath}<span class="${type}">${name}</span>` + ); link.appendChild(resultName); const description = document.createElement("div"); diff --git a/src/librustdoc/html/templates/item_info.html b/src/librustdoc/html/templates/item_info.html index d2ea9bdae9c..9e65ae95e15 100644 --- a/src/librustdoc/html/templates/item_info.html +++ b/src/librustdoc/html/templates/item_info.html @@ -1,5 +1,5 @@ {% if !items.is_empty() %} - <span class="item-info"> {# #} + <span class="item-info"> {% for item in items %} {{item|safe}} {# #} {% endfor %} diff --git a/src/librustdoc/html/templates/item_union.html b/src/librustdoc/html/templates/item_union.html index a01457971c1..f6d2fa34890 100644 --- a/src/librustdoc/html/templates/item_union.html +++ b/src/librustdoc/html/templates/item_union.html @@ -4,14 +4,15 @@ </code></pre> {{ self.document() | safe }} {% if self.fields_iter().peek().is_some() %} - <h2 id="fields" class="fields small-section-header"> - Fields<a href="#fields" class="anchor">§</a> + <h2 id="fields" class="fields small-section-header"> {# #} + Fields<a href="#fields" class="anchor">§</a> {# #} </h2> {% for (field, ty) in self.fields_iter() %} {% let name = field.name.expect("union field name") %} - <span id="structfield.{{ name }}" class="{{ ItemType::StructField }} small-section-header"> - <a href="#structfield.{{ name }}" class="anchor field">§</a> - <code>{{ name }}: {{ self.print_ty(ty) | safe }}</code> + <span id="structfield.{{ name }}" {#+ #} + class="{{ ItemType::StructField +}} small-section-header"> {# #} + <a href="#structfield.{{ name }}" class="anchor field">§</a> {# #} + <code>{{ name }}: {{+ self.print_ty(ty) | safe }}</code> {# #} </span> {% if let Some(stability_class) = self.stability_field(field) %} <span class="stab {{ stability_class }}"></span> diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 9133f899af6..759c4fd6012 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -31,6 +31,7 @@ data-themes="{{themes|join(",") }}" {#+ #} data-resource-suffix="{{page.resource_suffix}}" {#+ #} data-rustdoc-version="{{rustdoc_version}}" {#+ #} + data-channel="{{rust_channel}}" {#+ #} data-search-js="{{files.search_js}}" {#+ #} data-settings-js="{{files.settings_js}}" {#+ #} data-settings-css="{{files.settings_css}}" {#+ #} diff --git a/src/librustdoc/html/templates/print_item.html b/src/librustdoc/html/templates/print_item.html index edabac9a082..68a295ae095 100644 --- a/src/librustdoc/html/templates/print_item.html +++ b/src/librustdoc/html/templates/print_item.html @@ -1,5 +1,5 @@ <div class="main-heading"> {# #} - <h1> {# #} + <h1> {{typ}} {# The breadcrumbs of the item path, like std::string #} {% for component in path_components %} @@ -12,7 +12,7 @@ alt="Copy item path"> {# #} </button> {# #} </h1> {# #} - <span class="out-of-band"> {# #} + <span class="out-of-band"> {% if !stability_since_raw.is_empty() %} {{ stability_since_raw|safe +}} · {#+ #} {% endif %} diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 972b0c5ec19..e2e38d3e79f 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -6,7 +6,7 @@ use rustc_span::symbol::sym; use std::mem; use crate::clean; -use crate::clean::{Item, ItemIdSet, NestedAttributesExt}; +use crate::clean::{Item, ItemIdSet}; use crate::core::DocContext; use crate::fold::{strip_item, DocFolder}; use crate::passes::{ImplStripper, Pass}; @@ -85,7 +85,7 @@ impl<'a, 'tcx> Stripper<'a, 'tcx> { impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> { fn fold_item(&mut self, i: Item) -> Option<Item> { - let has_doc_hidden = i.attrs.lists(sym::doc).has_word(sym::hidden); + let has_doc_hidden = i.is_doc_hidden(); let is_impl_or_exported_macro = match *i.kind { clean::ImplItem(..) => true, // If the macro has the `#[macro_export]` attribute, it means it's accessible at the diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index 73fc26a6b04..90c361d9d28 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -1,10 +1,9 @@ //! A collection of utility functions for the `strip_*` passes. use rustc_hir::def_id::DefId; use rustc_middle::ty::{TyCtxt, Visibility}; -use rustc_span::symbol::sym; use std::mem; -use crate::clean::{self, Item, ItemId, ItemIdSet, NestedAttributesExt}; +use crate::clean::{self, Item, ItemId, ItemIdSet}; use crate::fold::{strip_item, DocFolder}; use crate::formats::cache::Cache; use crate::visit_lib::RustdocEffectiveVisibilities; @@ -163,7 +162,7 @@ impl<'a> ImplStripper<'a, '_> { // If the "for" item is exported and the impl block isn't `#[doc(hidden)]`, then we // need to keep it. self.cache.effective_visibilities.is_exported(self.tcx, for_def_id) - && !item.attrs.lists(sym::doc).has_word(sym::hidden) + && !item.is_doc_hidden() } else { false } @@ -240,7 +239,7 @@ impl<'tcx> ImportStripper<'tcx> { // FIXME: This should be handled the same way as for HTML output. imp.imported_item_is_doc_hidden(self.tcx) } else { - i.attrs.lists(sym::doc).has_word(sym::hidden) + i.is_doc_hidden() } } } @@ -249,7 +248,7 @@ impl<'tcx> DocFolder for ImportStripper<'tcx> { fn fold_item(&mut self, i: Item) -> Option<Item> { match *i.kind { clean::ImportItem(imp) if self.import_should_be_hidden(&i, &imp) => None, - clean::ImportItem(_) if i.attrs.lists(sym::doc).has_word(sym::hidden) => None, + clean::ImportItem(_) if i.is_doc_hidden() => None, clean::ExternCrateItem { .. } | clean::ImportItem(..) if i.visibility(self.tcx) != Some(Visibility::Public) => { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 22c8cc09243..fcf591a9328 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -313,7 +313,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { return false; } - let ret = match tcx.hir().get_by_def_id(res_did) { + let inlined = match tcx.hir().get_by_def_id(res_did) { // Bang macros are handled a bit on their because of how they are handled by the // compiler. If they have `#[doc(hidden)]` and the re-export doesn't have // `#[doc(inline)]`, then we don't inline it. @@ -344,7 +344,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { _ => false, }; self.view_item_stack.remove(&res_did); - ret + if inlined { + self.cx.cache.inlined_items.insert(res_did.to_def_id()); + } + inlined } /// Returns `true` if the item is visible, meaning it's not `#[doc(hidden)]` or private. diff --git a/src/tools/build_helper/src/ci.rs b/src/tools/build_helper/src/ci.rs index d106e5b339b..893195b69c2 100644 --- a/src/tools/build_helper/src/ci.rs +++ b/src/tools/build_helper/src/ci.rs @@ -4,8 +4,6 @@ use std::process::Command; pub enum CiEnv { /// Not a CI environment. None, - /// The Azure Pipelines environment, for Linux (including Docker), Windows, and macOS builds. - AzurePipelines, /// The GitHub Actions environment, for Linux (including Docker), Windows and macOS builds. GitHubActions, } @@ -13,9 +11,7 @@ pub enum CiEnv { impl CiEnv { /// Obtains the current CI environment. pub fn current() -> CiEnv { - if std::env::var("TF_BUILD").map_or(false, |e| e == "True") { - CiEnv::AzurePipelines - } else if std::env::var("GITHUB_ACTIONS").map_or(false, |e| e == "true") { + if std::env::var("GITHUB_ACTIONS").map_or(false, |e| e == "true") { CiEnv::GitHubActions } else { CiEnv::None diff --git a/src/tools/build_helper/src/util.rs b/src/tools/build_helper/src/util.rs index 731095023a9..11b8a228b8a 100644 --- a/src/tools/build_helper/src/util.rs +++ b/src/tools/build_helper/src/util.rs @@ -25,17 +25,21 @@ pub fn fail(s: &str) -> ! { detail_exit(1, cfg!(test)); } -pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool { +pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> Result<(), ()> { let status = match cmd.status() { Ok(status) => status, Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)), }; - if !status.success() && print_cmd_on_fail { - println!( - "\n\ncommand did not execute successfully: {:?}\n\ - expected success, got: {}\n\n", - cmd, status - ); + if !status.success() { + if print_cmd_on_fail { + println!( + "\n\ncommand did not execute successfully: {:?}\n\ + expected success, got: {}\n\n", + cmd, status + ); + } + Err(()) + } else { + Ok(()) } - status.success() } diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 0c14026aa84ee2ec4c67460c0a18abc8519ca6b +Subproject 03bc66b55c290324bd46eb22e369c8fae1908f9 diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index dbaf6aaa853..ee6aef71980 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -26,7 +26,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::{Rvalue, StatementKind}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{ - self, Binder, BoundVariableKind, Clause, EarlyBinder, FnSig, GenericArgKind, List, ParamEnv, ParamTy, + self, Binder, BoundVariableKind, ClauseKind, EarlyBinder, FnSig, GenericArgKind, List, ParamEnv, ParamTy, PredicateKind, ProjectionPredicate, Ty, TyCtxt, TypeVisitableExt, TypeckResults, }; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -1133,7 +1133,7 @@ fn needless_borrow_impl_arg_position<'tcx>( let projection_predicates = predicates .iter() .filter_map(|predicate| { - if let PredicateKind::Clause(Clause::Projection(projection_predicate)) = predicate.kind().skip_binder() { + if let PredicateKind::Clause(ClauseKind::Projection(projection_predicate)) = predicate.kind().skip_binder() { Some(projection_predicate) } else { None @@ -1147,7 +1147,7 @@ fn needless_borrow_impl_arg_position<'tcx>( if predicates .iter() .filter_map(|predicate| { - if let PredicateKind::Clause(Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() + if let PredicateKind::Clause(ClauseKind::Trait(trait_predicate)) = predicate.kind().skip_binder() && trait_predicate.trait_ref.self_ty() == param_ty.to_ty(cx.tcx) { Some(trait_predicate.trait_ref.def_id) @@ -1209,7 +1209,7 @@ fn needless_borrow_impl_arg_position<'tcx>( } predicates.iter().all(|predicate| { - if let PredicateKind::Clause(Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() + if let PredicateKind::Clause(ClauseKind::Trait(trait_predicate)) = predicate.kind().skip_binder() && cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id) && let ty::Param(param_ty) = trait_predicate.self_ty().kind() && let GenericArgKind::Type(ty) = substs_with_referent_ty[param_ty.index as usize].unpack() diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 8f5d319cd4f..8d84e756ff8 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -14,7 +14,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::traits::Reveal; use rustc_middle::ty::{ - self, Binder, BoundConstness, Clause, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, + self, Binder, BoundConstness, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate, Ty, TyCtxt, }; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -503,7 +503,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> let ty_predicates = tcx.predicates_of(did).predicates; for (p, _) in ty_predicates { - if let PredicateKind::Clause(Clause::Trait(p)) = p.kind().skip_binder() + if let PredicateKind::Clause(ClauseKind::Trait(p)) = p.kind().skip_binder() && p.trait_ref.def_id == eq_trait_id && let ty::Param(self_ty) = p.trait_ref.self_ty().kind() && p.constness == BoundConstness::NotConst @@ -516,7 +516,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> ParamEnv::new( tcx.mk_predicates_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain( params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| { - tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(Clause::Trait(TraitPredicate { + tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]), constness: BoundConstness::NotConst, polarity: ImplPolarity::Positive, diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index d1314795f58..818ebd1134d 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -4,7 +4,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, AliasTy, Clause, PredicateKind}; +use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; @@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { let preds = cx.tcx.explicit_item_bounds(def_id); let mut is_future = false; for (p, _span) in preds.subst_iter_copied(cx.tcx, substs) { - if let Some(trait_pred) = p.to_opt_poly_trait_pred() { + if let Some(trait_pred) = p.as_trait_clause() { if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() { is_future = true; break; @@ -93,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { infcx .err_ctxt() .maybe_note_obligation_cause_for_async_await(db, &obligation); - if let PredicateKind::Clause(Clause::Trait(trait_pred)) = + if let PredicateKind::Clause(ClauseKind::Trait(trait_pred)) = obligation.predicate.kind().skip_binder() { db.note(format!( diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index 99f810c27cf..cf85d3174db 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -16,7 +16,7 @@ use rustc_hir::{ }; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::{self, AssocKind, Clause, EarlyBinder, GenericArg, GenericArgKind, PredicateKind, Ty}; +use rustc_middle::ty::{self, AssocKind, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, PredicateKind, Ty}; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol}; @@ -175,7 +175,7 @@ fn check_collect_into_intoiterator<'tcx>( .caller_bounds() .into_iter() .filter_map(|p| { - if let PredicateKind::Clause(Clause::Trait(t)) = p.kind().skip_binder() + if let PredicateKind::Clause(ClauseKind::Trait(t)) = p.kind().skip_binder() && cx.tcx.is_diagnostic_item(sym::IntoIterator,t.trait_ref.def_id) { Some(t.self_ty()) } else { diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 309d2157b76..06fa95cd657 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -14,7 +14,7 @@ use rustc_lint::LateContext; use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; -use rustc_middle::ty::{self, Clause, EarlyBinder, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty}; +use rustc_middle::ty::{self, ClauseKind, EarlyBinder, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty}; use rustc_span::{sym, Symbol}; use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause}; @@ -345,12 +345,12 @@ fn get_input_traits_and_projections<'tcx>( let mut projection_predicates = Vec::new(); for predicate in cx.tcx.param_env(callee_def_id).caller_bounds() { match predicate.kind().skip_binder() { - PredicateKind::Clause(Clause::Trait(trait_predicate)) => { + PredicateKind::Clause(ClauseKind::Trait(trait_predicate)) => { if trait_predicate.trait_ref.self_ty() == input { trait_predicates.push(trait_predicate); } }, - PredicateKind::Clause(Clause::Projection(projection_predicate)) => { + PredicateKind::Clause(ClauseKind::Projection(projection_predicate)) => { if projection_predicate.projection_ty.self_ty() == input { projection_predicates.push(projection_predicate); } @@ -407,7 +407,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< let mut trait_predicates = cx.tcx.param_env(callee_def_id) .caller_bounds().iter().filter(|predicate| { - if let PredicateKind::Clause(Clause::Trait(trait_predicate)) + if let PredicateKind::Clause(ClauseKind::Trait(trait_predicate)) = predicate.kind().skip_binder() && trait_predicate.trait_ref.self_ty() == *param_ty { diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 7d53fe65658..3773975e955 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { .filter_map(|pred| { // Note that we do not want to deal with qualified predicates here. match pred.kind().no_bound_vars() { - Some(ty::PredicateKind::Clause(ty::Clause::Trait(pred))) if pred.def_id() != sized_trait => { + Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))) if pred.def_id() != sized_trait => { Some(pred) }, _ => None, diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index fc550936165..b8911f10907 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -19,7 +19,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::{self, Binder, Clause, ExistentialPredicate, List, PredicateKind, Ty}; +use rustc_middle::ty::{self, Binder, ClauseKind, ExistentialPredicate, List, PredicateKind, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::sym; @@ -697,7 +697,7 @@ fn matches_preds<'tcx>( ObligationCause::dummy(), cx.param_env, cx.tcx - .mk_predicate(Binder::dummy(PredicateKind::Clause(Clause::Projection( + .mk_predicate(Binder::dummy(PredicateKind::Clause(ClauseKind::Projection( p.with_self_ty(cx.tcx, ty), )))), )), diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs index 289ca4e9bed..a375e5d5b4c 100644 --- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs +++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs @@ -4,7 +4,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{Closure, Expr, ExprKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_middle::ty::{Clause, GenericPredicates, PredicateKind, ProjectionPredicate, TraitPredicate}; +use rustc_middle::ty::{ClauseKind, GenericPredicates, PredicateKind, ProjectionPredicate, TraitPredicate}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, BytePos, Span}; @@ -45,7 +45,7 @@ fn get_trait_predicates_for_trait_id<'tcx>( let mut preds = Vec::new(); for (pred, _) in generics.predicates { if_chain! { - if let PredicateKind::Clause(Clause::Trait(poly_trait_pred)) = pred.kind().skip_binder(); + if let PredicateKind::Clause(ClauseKind::Trait(poly_trait_pred)) = pred.kind().skip_binder(); let trait_pred = cx.tcx.erase_late_bound_regions(pred.kind().rebind(poly_trait_pred)); if let Some(trait_def_id) = trait_id; if trait_def_id == trait_pred.trait_ref.def_id; @@ -63,7 +63,7 @@ fn get_projection_pred<'tcx>( trait_pred: TraitPredicate<'tcx>, ) -> Option<ProjectionPredicate<'tcx>> { generics.predicates.iter().find_map(|(proj_pred, _)| { - if let ty::PredicateKind::Clause(Clause::Projection(pred)) = proj_pred.kind().skip_binder() { + if let ty::PredicateKind::Clause(ClauseKind::Projection(pred)) = proj_pred.kind().skip_binder() { let projection_pred = cx.tcx.erase_late_bound_regions(proj_pred.kind().rebind(pred)); if projection_pred.projection_ty.substs == trait_pred.trait_ref.substs { return Some(projection_pred); diff --git a/src/tools/clippy/clippy_lints/src/unnamed_address.rs b/src/tools/clippy/clippy_lints/src/unnamed_address.rs index 0bcafde658a..0f5cdb6aaea 100644 --- a/src/tools/clippy/clippy_lints/src/unnamed_address.rs +++ b/src/tools/clippy/clippy_lints/src/unnamed_address.rs @@ -96,9 +96,7 @@ impl LateLintPass<'_> for UnnamedAddress { if let ExprKind::Call(func, [ref _left, ref _right]) = expr.kind; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::PTR_EQ) || - match_def_path(cx, def_id, &paths::RC_PTR_EQ) || - match_def_path(cx, def_id, &paths::ARC_PTR_EQ); + if match_def_path(cx, def_id, &paths::PTR_EQ); let ty_param = cx.typeck_results().node_substs(func.hir_id).type_at(0); if ty_param.is_trait(); then { diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index 3df40942e7b..941df3318ae 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -73,7 +73,7 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: .flat_map(|v| v.fields.iter()) .any(|x| matches!(cx.tcx.type_of(x.did).subst_identity().peel_refs().kind(), ty::Param(_))) && all_predicates_of(cx.tcx, fn_id).all(|(pred, _)| match pred.kind().skip_binder() { - PredicateKind::Clause(ty::Clause::Trait(pred)) => cx.tcx.trait_def(pred.trait_ref.def_id).is_marker, + PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => cx.tcx.trait_def(pred.trait_ref.def_id).is_marker, _ => true, }) && subs.types().all(|x| matches!(x.peel_refs().kind(), ty::Param(_))) diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index 38ee84fb76c..0e6f01287b5 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -15,7 +15,6 @@ pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [ ]; #[cfg(feature = "internal")] pub const DIAGNOSTIC_BUILDER: [&str; 3] = ["rustc_errors", "diagnostic_builder", "DiagnosticBuilder"]; -pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"]; pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"]; pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"]; pub const BTREESET_ITER: [&str; 6] = ["alloc", "collections", "btree", "set", "BTreeSet", "iter"]; @@ -93,7 +92,6 @@ pub const PTR_WRITE_UNALIGNED: [&str; 3] = ["core", "ptr", "write_unaligned"]; pub const PTR_WRITE_VOLATILE: [&str; 3] = ["core", "ptr", "write_volatile"]; pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"]; pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"]; -pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"]; pub const REFCELL_REF: [&str; 3] = ["core", "cell", "Ref"]; pub const REFCELL_REFMUT: [&str; 3] = ["core", "cell", "RefMut"]; pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"]; diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 860a489494c..a10eb8646af 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -27,14 +27,14 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) for (predicate, _) in predicates.predicates { match predicate.kind().skip_binder() { ty::PredicateKind::Clause( - ty::Clause::RegionOutlives(_) - | ty::Clause::TypeOutlives(_) - | ty::Clause::Projection(_) - | ty::Clause::Trait(..) - | ty::Clause::ConstArgHasType(..), + ty::ClauseKind::RegionOutlives(_) + | ty::ClauseKind::TypeOutlives(_) + | ty::ClauseKind::Projection(_) + | ty::ClauseKind::Trait(..) + | ty::ClauseKind::ConstArgHasType(..), ) - | ty::PredicateKind::Clause(ty::Clause::WellFormed(_)) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue, ty::PredicateKind::AliasRelate(..) => panic!("alias relate predicate on function: {predicate:#?}"), @@ -317,7 +317,7 @@ fn check_terminator<'tcx>( TerminatorKind::Call { func, args, - from_hir_call: _, + call_source: _, destination: _, target: _, unwind: _, diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index f477524eec5..a87d58110b0 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -211,6 +211,7 @@ impl<'a> Sugg<'a> { | ast::ExprKind::Path(..) | ast::ExprKind::Repeat(..) | ast::ExprKind::Ret(..) + | ast::ExprKind::Become(..) | ast::ExprKind::Yeet(..) | ast::ExprKind::FormatArgs(..) | ast::ExprKind::Struct(..) diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 7b4ed77e8ed..2b185943c59 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -94,7 +94,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' match predicate.kind().skip_binder() { // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through // and check substitutions to find `U`. - ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => { + ty::ClauseKind::Trait(trait_predicate) => { if trait_predicate .trait_ref .substs @@ -107,7 +107,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' }, // For `impl Trait<Assoc=U>`, it will register a predicate of `<T as Trait>::Assoc = U`, // so we check the term for `U`. - ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate)) => { + ty::ClauseKind::Projection(projection_predicate) => { if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() { if contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen) { return true; @@ -268,7 +268,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)), ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { for (predicate, _) in cx.tcx.explicit_item_bounds(def_id).skip_binder() { - if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() { + if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() { if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) { return true; } @@ -665,7 +665,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => sig_from_bounds( cx, ty, - cx.tcx.item_bounds(def_id).subst(cx.tcx, substs), + cx.tcx.item_bounds(def_id).subst_iter(cx.tcx, substs).map(|c| c.as_predicate()), cx.tcx.opt_parent(def_id), ), ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)), @@ -698,7 +698,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t fn sig_from_bounds<'tcx>( cx: &LateContext<'tcx>, ty: Ty<'tcx>, - predicates: &'tcx [Predicate<'tcx>], + predicates: impl IntoIterator<Item = Predicate<'tcx>>, predicates_id: Option<DefId>, ) -> Option<ExprFnSig<'tcx>> { let mut inputs = None; @@ -707,7 +707,7 @@ fn sig_from_bounds<'tcx>( for pred in predicates { match pred.kind().skip_binder() { - PredicateKind::Clause(ty::Clause::Trait(p)) + PredicateKind::Clause(ty::ClauseKind::Trait(p)) if (lang_items.fn_trait() == Some(p.def_id()) || lang_items.fn_mut_trait() == Some(p.def_id()) || lang_items.fn_once_trait() == Some(p.def_id())) @@ -720,7 +720,7 @@ fn sig_from_bounds<'tcx>( } inputs = Some(i); }, - PredicateKind::Clause(ty::Clause::Projection(p)) + PredicateKind::Clause(ty::ClauseKind::Projection(p)) if Some(p.projection_ty.def_id) == lang_items.fn_once_output() && p.projection_ty.self_ty() == ty => { if output.is_some() { @@ -747,7 +747,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option .subst_iter_copied(cx.tcx, ty.substs) { match pred.kind().skip_binder() { - PredicateKind::Clause(ty::Clause::Trait(p)) + ty::ClauseKind::Trait(p) if (lang_items.fn_trait() == Some(p.def_id()) || lang_items.fn_mut_trait() == Some(p.def_id()) || lang_items.fn_once_trait() == Some(p.def_id())) => @@ -760,7 +760,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option } inputs = Some(i); }, - PredicateKind::Clause(ty::Clause::Projection(p)) + ty::ClauseKind::Projection(p) if Some(p.projection_ty.def_id) == lang_items.fn_once_output() => { if output.is_some() { @@ -950,7 +950,7 @@ pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tc predicates .iter() .try_fold(false, |found, p| { - if let PredicateKind::Clause(ty::Clause::Trait(p)) = p.kind().skip_binder() + if let PredicateKind::Clause(ty::ClauseKind::Trait(p)) = p.kind().skip_binder() && let ty::Param(self_ty) = p.trait_ref.self_ty().kind() && ty.index == self_ty.index { diff --git a/src/tools/clippy/tests/ui/from_over_into_unfixable.rs b/src/tools/clippy/tests/ui/from_over_into_unfixable.rs index bd62c655216..3b280b7488a 100644 --- a/src/tools/clippy/tests/ui/from_over_into_unfixable.rs +++ b/src/tools/clippy/tests/ui/from_over_into_unfixable.rs @@ -32,10 +32,4 @@ impl Into<u8> for ContainsVal { } } -type Opaque = impl Sized; -struct IntoOpaque; -impl Into<Opaque> for IntoOpaque { - fn into(self) -> Opaque {} -} - fn main() {} diff --git a/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr b/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr index bb966af4b0f..251f1d84e74 100644 --- a/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr +++ b/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr @@ -1,12 +1,29 @@ -error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/from_over_into_unfixable.rs:35:15 +error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true + --> $DIR/from_over_into_unfixable.rs:11:1 | -LL | type Opaque = impl Sized; - | ^^^^^^^^^^ +LL | impl Into<InMacro> for String { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information - = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable + = help: replace the `Into` implementation with `From<std::string::String>` + = note: `-D clippy::from-over-into` implied by `-D warnings` -error: aborting due to previous error +error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true + --> $DIR/from_over_into_unfixable.rs:19:1 + | +LL | impl Into<WeirdUpperSelf> for &'static [u8] { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: replace the `Into` implementation with `From<&'static [u8]>` + +error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true + --> $DIR/from_over_into_unfixable.rs:28:1 + | +LL | impl Into<u8> for ContainsVal { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `impl From<Local> for Foreign` is allowed by the orphan rules, for more information see + https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence + = help: replace the `Into` implementation with `From<ContainsVal>` + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0658`. diff --git a/src/tools/clippy/tests/ui/vtable_address_comparisons.rs b/src/tools/clippy/tests/ui/vtable_address_comparisons.rs index a9a4a0f5a6b..99c3f468f04 100644 --- a/src/tools/clippy/tests/ui/vtable_address_comparisons.rs +++ b/src/tools/clippy/tests/ui/vtable_address_comparisons.rs @@ -23,12 +23,6 @@ fn main() { let b = &1 as &dyn Debug; ptr::eq(a, b); - let a: Rc<dyn Debug> = Rc::new(1); - Rc::ptr_eq(&a, &a); - - let a: Arc<dyn Debug> = Arc::new(1); - Arc::ptr_eq(&a, &a); - // These should be fine: let a = &1; ptr::eq(a, a); @@ -39,6 +33,12 @@ fn main() { let a = Arc::new(1); Arc::ptr_eq(&a, &a); + let a: Rc<dyn Debug> = Rc::new(1); + Rc::ptr_eq(&a, &a); + + let a: Arc<dyn Debug> = Arc::new(1); + Arc::ptr_eq(&a, &a); + let a: &[u8] = b""; ptr::eq(a, a); } diff --git a/src/tools/clippy/tests/ui/vtable_address_comparisons.stderr b/src/tools/clippy/tests/ui/vtable_address_comparisons.stderr index 14748f583f0..7b866d274d5 100644 --- a/src/tools/clippy/tests/ui/vtable_address_comparisons.stderr +++ b/src/tools/clippy/tests/ui/vtable_address_comparisons.stderr @@ -63,21 +63,5 @@ LL | ptr::eq(a, b); | = help: consider extracting and comparing data pointers only -error: comparing trait object pointers compares a non-unique vtable address - --> $DIR/vtable_address_comparisons.rs:27:5 - | -LL | Rc::ptr_eq(&a, &a); - | ^^^^^^^^^^^^^^^^^^ - | - = help: consider extracting and comparing data pointers only - -error: comparing trait object pointers compares a non-unique vtable address - --> $DIR/vtable_address_comparisons.rs:30:5 - | -LL | Arc::ptr_eq(&a, &a); - | ^^^^^^^^^^^^^^^^^^^ - | - = help: consider extracting and comparing data pointers only - -error: aborting due to 10 previous errors +error: aborting due to 8 previous errors diff --git a/src/tools/miri/test-cargo-miri/run-test.py b/src/tools/miri/test-cargo-miri/run-test.py index 9df90c725e4..f022c51e59f 100755 --- a/src/tools/miri/test-cargo-miri/run-test.py +++ b/src/tools/miri/test-cargo-miri/run-test.py @@ -5,7 +5,11 @@ Assumes the `MIRI_SYSROOT` env var to be set appropriately, and the working directory to contain the cargo-miri-test project. ''' -import sys, subprocess, os, re, difflib +import difflib +import os +import re +import sys +import subprocess CGREEN = '\33[32m' CBOLD = '\33[1m' @@ -46,7 +50,9 @@ def check_output(actual, path, name): print(f"--- END diff {name} ---") return False -def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): +def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env=None): + if env is None: + env = {} print("Testing {}...".format(name)) ## Call `cargo miri`, capture all output p_env = os.environ.copy() @@ -64,13 +70,15 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): stdout_matches = check_output(stdout, stdout_ref, "stdout") stderr_matches = check_output(stderr, stderr_ref, "stderr") - + if p.returncode == 0 and stdout_matches and stderr_matches: # All good! return fail("exit code was {}".format(p.returncode)) -def test_no_rebuild(name, cmd, env={}): +def test_no_rebuild(name, cmd, env=None): + if env is None: + env = {} print("Testing {}...".format(name)) p_env = os.environ.copy() p_env.update(env) @@ -84,13 +92,13 @@ def test_no_rebuild(name, cmd, env={}): stdout = stdout.decode("UTF-8") stderr = stderr.decode("UTF-8") if p.returncode != 0: - fail("rebuild failed"); + fail("rebuild failed") # Also check for 'Running' as a sanity check. if stderr.count(" Compiling ") > 0 or stderr.count(" Running ") == 0: print("--- BEGIN stderr ---") print(stderr, end="") print("--- END stderr ---") - fail("Something was being rebuilt when it should not be (or we got no output)"); + fail("Something was being rebuilt when it should not be (or we got no output)") def test_cargo_miri_run(): test("`cargo miri run` (no isolation)", diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 2018c239ba0..f9421117eaa 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -22,7 +22,7 @@ except ImportError: import urllib.request as urllib2 from urllib.error import HTTPError try: - import typing + import typing # noqa: F401 FIXME: py2 except ImportError: pass @@ -152,8 +152,8 @@ def update_latest( latest = json.load(f, object_pairs_hook=collections.OrderedDict) current_status = { - os: read_current_status(current_commit, 'history/' + os + '.tsv') - for os in ['windows', 'linux'] + os_: read_current_status(current_commit, 'history/' + os_ + '.tsv') + for os_ in ['windows', 'linux'] } slug = 'rust-lang/rust' @@ -170,10 +170,10 @@ def update_latest( changed = False create_issue_for_status = None # set to the status that caused the issue - for os, s in current_status.items(): - old = status[os] + for os_, s in current_status.items(): + old = status[os_] new = s.get(tool, old) - status[os] = new + status[os_] = new maintainers = ' '.join('@'+name for name in MAINTAINERS.get(tool, ())) # comparing the strings, but they are ordered appropriately: # "test-pass" > "test-fail" > "build-fail" @@ -181,12 +181,12 @@ def update_latest( # things got fixed or at least the status quo improved changed = True message += '🎉 {} on {}: {} → {} (cc {}).\n' \ - .format(tool, os, old, new, maintainers) + .format(tool, os_, old, new, maintainers) elif new < old: # tests or builds are failing and were not failing before changed = True title = '💔 {} on {}: {} → {}' \ - .format(tool, os, old, new) + .format(tool, os_, old, new) message += '{} (cc {}).\n' \ .format(title, maintainers) # See if we need to create an issue. diff --git a/src/tools/rust-analyzer/.github/workflows/autopublish.yaml b/src/tools/rust-analyzer/.github/workflows/autopublish.yaml index 7090c94d93c..15cedab1272 100644 --- a/src/tools/rust-analyzer/.github/workflows/autopublish.yaml +++ b/src/tools/rust-analyzer/.github/workflows/autopublish.yaml @@ -28,7 +28,7 @@ jobs: - name: Publish Crates env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} - PATCH: ${{ github.run_number }} + RUN_NUMBER: ${{ github.run_number }} shell: bash run: | git config --global user.email "runner@gha.local" @@ -53,4 +53,4 @@ jobs: # Remove library crates from the workspaces so we don't auto-publish them as well sed -i 's/ "lib\/\*",//' ./Cargo.toml find crates/rust-analyzer -type f -name '*.rs' -exec sed -i 's/rust_analyzer/ra_ap_rust_analyzer/g' {} + - cargo workspaces publish --yes --force '*' --exact --no-git-commit --allow-dirty --skip-published custom 0.0.$PATCH + cargo workspaces publish --yes --force '*' --exact --no-git-commit --allow-dirty --skip-published custom 0.0.$(($RUN_NUMBER + 133)) diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml index 622da105fdd..31bb7eed8d7 100644 --- a/src/tools/rust-analyzer/.github/workflows/ci.yaml +++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml @@ -24,6 +24,7 @@ jobs: pull-requests: read outputs: typescript: ${{ steps.filter.outputs.typescript }} + proc_macros: ${{ steps.filter.outputs.proc_macros }} steps: - uses: actions/checkout@v3 - uses: dorny/paths-filter@4067d885736b84de7c414f582ac45897079b0a78 @@ -45,8 +46,8 @@ jobs: runs-on: ${{ matrix.os }} env: CC: deny_c - RUST_CHANNEL: "${{ needs.changes.outputs.proc_macros == 'true' && 'nightly' || 'stable'}}" - USE_SYSROOT_ABI: "${{ needs.changes.outputs.proc_macros == 'true' && '--features sysroot-abi' || ''}}" + RUST_CHANNEL: "${{ needs.changes.outputs.proc_macros == 'true' && 'nightly' || 'stable' }}" + USE_SYSROOT_ABI: "${{ needs.changes.outputs.proc_macros == 'true' && '--features sysroot-abi' || '' }}" strategy: fail-fast: false @@ -62,7 +63,8 @@ jobs: - name: Install Rust toolchain run: | rustup update --no-self-update ${{ env.RUST_CHANNEL }} - rustup component add rustfmt rust-src + rustup component add --toolchain ${{ env.RUST_CHANNEL }} rustfmt rust-src + rustup default ${{ env.RUST_CHANNEL }} - name: Cache Dependencies uses: Swatinem/rust-cache@988c164c3d0e93c4dbab36aaf5bbeb77425b2894 diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index e36aef6a6aa..50c81ca279e 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -177,21 +177,21 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chalk-derive" -version = "0.89.0" +version = "0.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea176c50987dc4765961aa165001e8eb5a722a26308c5797a47303ea91686aab" +checksum = "c59178fded594fe78c47b841520e5a4399d00fe15fffee19b945958a878cd02d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.15", "synstructure", ] [[package]] name = "chalk-ir" -version = "0.89.0" +version = "0.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473b480241695428c14e8f84f1c9a47ef232450a50faf3a4041e5c9dc11e0a3b" +checksum = "8824be92876823b828d551bb792f79eb1f69c69d1948abf69fccbf84e448e57b" dependencies = [ "bitflags 1.3.2", "chalk-derive", @@ -200,9 +200,9 @@ dependencies = [ [[package]] name = "chalk-recursive" -version = "0.89.0" +version = "0.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6764b4fe67cac3a3758185084efbfbd39bf0352795824ba849ddd2b64cd4bb28" +checksum = "1e110d1260809c238072d1c8ef84060e39983e8ea9d4c6f74b19b0ebbf8904dc" dependencies = [ "chalk-derive", "chalk-ir", @@ -213,9 +213,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.89.0" +version = "0.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55a7e6160966eceb6e7dcc2f479a2af4c477aaf5bccbc640d82515995ab1a6cc" +checksum = "12200b19abf4b0633095f7bd099f3ef609d314754b6adb358c68cc04d10589e5" dependencies = [ "chalk-derive", "chalk-ir", @@ -327,7 +327,7 @@ checksum = "f3cdeb9ec472d588e539a818b2dee436825730da08ad0017c4b1a17676bdc8b7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1505,7 +1505,6 @@ dependencies = [ "parking_lot 0.12.1", "parking_lot_core 0.9.6", "proc-macro-api", - "proc-macro-srv-cli", "profile", "project-model", "rayon", @@ -1578,7 +1577,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1637,7 +1636,7 @@ checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1660,7 +1659,7 @@ checksum = "395627de918015623b32e7669714206363a7fc00382bf477e72c1f7533e8eafc" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1731,14 +1730,25 @@ dependencies = [ ] [[package]] +name = "syn" +version = "2.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] name = "synstructure" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +checksum = "285ba80e733fac80aa4270fbcdf83772a79b80aa35c97075320abfee4a915b06" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.15", "unicode-xid", ] @@ -1811,7 +1821,7 @@ checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1913,7 +1923,7 @@ checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] diff --git a/src/tools/rust-analyzer/crates/base-db/src/fixture.rs b/src/tools/rust-analyzer/crates/base-db/src/fixture.rs index 5b11343173b..d3abc3870b7 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/fixture.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/fixture.rs @@ -215,7 +215,7 @@ impl ChangeFixture { None, default_cfg, Default::default(), - Env::default(), + Env::new_for_test_fixture(), false, CrateOrigin::Local { repo: None, name: None }, default_target_data_layout @@ -259,7 +259,7 @@ impl ChangeFixture { None, Default::default(), Default::default(), - Env::default(), + Env::new_for_test_fixture(), false, CrateOrigin::Lang(LangCrateOrigin::Core), target_layout.clone(), @@ -298,7 +298,7 @@ impl ChangeFixture { None, Default::default(), Default::default(), - Env::default(), + Env::new_for_test_fixture(), true, CrateOrigin::Local { repo: None, name: None }, target_layout, diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs index e8d521b42f8..f2e523675bc 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -151,6 +151,12 @@ pub enum CrateOrigin { Lang(LangCrateOrigin), } +impl CrateOrigin { + pub fn is_local(&self) -> bool { + matches!(self, CrateOrigin::Local { .. }) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum LangCrateOrigin { Alloc, @@ -333,6 +339,17 @@ pub struct Env { entries: FxHashMap<String, String>, } +impl Env { + pub fn new_for_test_fixture() -> Self { + Env { + entries: FxHashMap::from_iter([( + String::from("__ra_is_test_fixture"), + String::from("__ra_is_test_fixture"), + )]), + } + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Dependency { pub crate_id: CrateId, @@ -456,6 +473,12 @@ impl CrateGraph { self.arena.iter().map(|(idx, _)| idx) } + // FIXME: used for `handle_hack_cargo_workspace`, should be removed later + #[doc(hidden)] + pub fn iter_mut(&mut self) -> impl Iterator<Item = (CrateId, &mut CrateData)> + '_ { + self.arena.iter_mut() + } + /// Returns an iterator over all transitive dependencies of the given crate, /// including the crate itself. pub fn transitive_deps(&self, of: CrateId) -> impl Iterator<Item = CrateId> { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs index 36626ed1a9b..94dc39b1175 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs @@ -37,6 +37,9 @@ pub struct Body { pub pats: Arena<Pat>, pub bindings: Arena<Binding>, pub labels: Arena<Label>, + /// Id of the closure/generator that owns the corresponding binding. If a binding is owned by the + /// top level expression, it will not be listed in here. + pub binding_owners: FxHashMap<BindingId, ExprId>, /// The patterns for the function's parameters. While the parameter types are /// part of the function signature, the patterns are not (they don't change /// the external type of the function). @@ -118,7 +121,8 @@ impl Body { let _p = profile::span("body_with_source_map_query"); let mut params = None; - let (file_id, module, body, is_async_fn) = { + let mut is_async_fn = false; + let InFile { file_id, value: body } = { match def { DefWithBodyId::FunctionId(f) => { let data = db.function_data(f); @@ -138,31 +142,27 @@ impl Body { }), ) }); - ( - src.file_id, - f.module(db), - src.value.body().map(ast::Expr::from), - data.has_async_kw(), - ) + is_async_fn = data.has_async_kw(); + src.map(|it| it.body().map(ast::Expr::from)) } DefWithBodyId::ConstId(c) => { let c = c.lookup(db); let src = c.source(db); - (src.file_id, c.module(db), src.value.body(), false) + src.map(|it| it.body()) } DefWithBodyId::StaticId(s) => { let s = s.lookup(db); let src = s.source(db); - (src.file_id, s.module(db), src.value.body(), false) + src.map(|it| it.body()) } DefWithBodyId::VariantId(v) => { - let e = v.parent.lookup(db); let src = v.parent.child_source(db); - let variant = &src.value[v.local_id]; - (src.file_id, e.container, variant.expr(), false) + src.map(|it| it[v.local_id].expr()) } + DefWithBodyId::InTypeConstId(c) => c.lookup(db).id.map(|_| c.source(db).expr()), } }; + let module = def.module(db); let expander = Expander::new(db, file_id, module); let (mut body, source_map) = Body::new(db, def, expander, params, body, module.krate, is_async_fn); @@ -209,14 +209,24 @@ impl Body { } fn shrink_to_fit(&mut self) { - let Self { _c: _, body_expr: _, block_scopes, exprs, labels, params, pats, bindings } = - self; + let Self { + _c: _, + body_expr: _, + block_scopes, + exprs, + labels, + params, + pats, + bindings, + binding_owners, + } = self; block_scopes.shrink_to_fit(); exprs.shrink_to_fit(); labels.shrink_to_fit(); params.shrink_to_fit(); pats.shrink_to_fit(); bindings.shrink_to_fit(); + binding_owners.shrink_to_fit(); } pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) { @@ -260,6 +270,17 @@ impl Body { f(pat_id); self.walk_pats_shallow(pat_id, |p| self.walk_pats(p, f)); } + + pub fn is_binding_upvar(&self, binding: BindingId, relative_to: ExprId) -> bool { + match self.binding_owners.get(&binding) { + Some(x) => { + // We assign expression ids in a way that outer closures will receive + // a lower id + x.into_raw() < relative_to.into_raw() + } + None => true, + } + } } impl Default for Body { @@ -272,6 +293,7 @@ impl Default for Body { labels: Default::default(), params: Default::default(), block_scopes: Default::default(), + binding_owners: Default::default(), _c: Default::default(), } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs index 7b88e525bf1..b375ec63a67 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs @@ -11,7 +11,6 @@ use hir_expand::{ AstId, ExpandError, InFile, }; use intern::Interned; -use la_arena::Arena; use profile::Count; use rustc_hash::FxHashMap; use smallvec::SmallVec; @@ -40,7 +39,7 @@ use crate::{ nameres::{DefMap, MacroSubNs}, path::{GenericArgs, Path}, type_ref::{Mutability, Rawness, TypeRef}, - AdtId, BlockId, BlockLoc, DefWithBodyId, ModuleDefId, UnresolvedMacro, + AdtId, BlockId, BlockLoc, ConstBlockLoc, DefWithBodyId, ModuleDefId, UnresolvedMacro, }; pub(super) fn lower( @@ -60,10 +59,11 @@ pub(super) fn lower( source_map: BodySourceMap::default(), ast_id_map: db.ast_id_map(expander.current_file_id), body: Body { - exprs: Arena::default(), - pats: Arena::default(), - bindings: Arena::default(), - labels: Arena::default(), + exprs: Default::default(), + pats: Default::default(), + bindings: Default::default(), + binding_owners: Default::default(), + labels: Default::default(), params: Vec::new(), body_expr: dummy_expr_id(), block_scopes: Vec::new(), @@ -188,7 +188,7 @@ impl ExprCollector<'_> { param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false)) { let ptr = AstPtr::new(&self_param); - let binding_id = self.alloc_binding( + let binding_id: la_arena::Idx<Binding> = self.alloc_binding( name![self], BindingAnnotation::new( self_param.mut_token().is_some() && self_param.amp_token().is_none(), @@ -297,7 +297,10 @@ impl ExprCollector<'_> { let (result_expr_id, prev_binding_owner) = this.initialize_binding_owner(syntax_ptr); let inner_expr = this.collect_block(e); - let x = this.db.intern_anonymous_const((this.owner, inner_expr)); + let x = this.db.intern_anonymous_const(ConstBlockLoc { + parent: this.owner, + root: inner_expr, + }); this.body.exprs[result_expr_id] = Expr::Const(x); this.current_binding_owner = prev_binding_owner; result_expr_id @@ -742,16 +745,14 @@ impl ExprCollector<'_> { /// } /// ``` fn collect_for_loop(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::ForExpr) -> ExprId { - let (into_iter_fn, iter_next_fn, option_some, option_none) = 'if_chain: { - if let Some(into_iter_fn) = LangItem::IntoIterIntoIter.path(self.db, self.krate) { - if let Some(iter_next_fn) = LangItem::IteratorNext.path(self.db, self.krate) { - if let Some(option_some) = LangItem::OptionSome.path(self.db, self.krate) { - if let Some(option_none) = LangItem::OptionNone.path(self.db, self.krate) { - break 'if_chain (into_iter_fn, iter_next_fn, option_some, option_none); - } - } - } - } + let Some((into_iter_fn, iter_next_fn, option_some, option_none)) = (|| { + Some(( + LangItem::IntoIterIntoIter.path(self.db, self.krate)?, + LangItem::IteratorNext.path(self.db, self.krate)?, + LangItem::OptionSome.path(self.db, self.krate)?, + LangItem::OptionNone.path(self.db, self.krate)?, + )) + })() else { // Some of the needed lang items are missing, so we can't desugar return self.alloc_expr(Expr::Missing, syntax_ptr); }; @@ -784,8 +785,8 @@ impl ExprCollector<'_> { }), }; let iter_name = Name::generate_new_name(); - let iter_binding = self.alloc_binding(iter_name.clone(), BindingAnnotation::Mutable); - let iter_expr = self.alloc_expr(Expr::Path(Path::from(iter_name)), syntax_ptr.clone()); + let iter_expr = + self.alloc_expr(Expr::Path(Path::from(iter_name.clone())), syntax_ptr.clone()); let iter_expr_mut = self.alloc_expr( Expr::Ref { expr: iter_expr, rawness: Rawness::Ref, mutability: Mutability::Mut }, syntax_ptr.clone(), @@ -805,7 +806,9 @@ impl ExprCollector<'_> { ); let loop_outer = self.alloc_expr(Expr::Loop { body: loop_inner, label }, syntax_ptr.clone()); + let iter_binding = self.alloc_binding(iter_name, BindingAnnotation::Mutable); let iter_pat = self.alloc_pat_desugared(Pat::Bind { id: iter_binding, subpat: None }); + self.add_definition_to_binding(iter_binding, iter_pat); self.alloc_expr( Expr::Match { expr: iterator, @@ -827,18 +830,14 @@ impl ExprCollector<'_> { /// } /// ``` fn collect_try_operator(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::TryExpr) -> ExprId { - let (try_branch, cf_continue, cf_break, try_from_residual) = 'if_chain: { - if let Some(try_branch) = LangItem::TryTraitBranch.path(self.db, self.krate) { - if let Some(cf_continue) = LangItem::ControlFlowContinue.path(self.db, self.krate) { - if let Some(cf_break) = LangItem::ControlFlowBreak.path(self.db, self.krate) { - if let Some(try_from_residual) = - LangItem::TryTraitFromResidual.path(self.db, self.krate) - { - break 'if_chain (try_branch, cf_continue, cf_break, try_from_residual); - } - } - } - } + let Some((try_branch, cf_continue, cf_break, try_from_residual)) = (|| { + Some(( + LangItem::TryTraitBranch.path(self.db, self.krate)?, + LangItem::ControlFlowContinue.path(self.db, self.krate)?, + LangItem::ControlFlowBreak.path(self.db, self.krate)?, + LangItem::TryTraitFromResidual.path(self.db, self.krate)?, + )) + })() else { // Some of the needed lang items are missing, so we can't desugar return self.alloc_expr(Expr::Missing, syntax_ptr); }; @@ -1541,13 +1540,16 @@ impl ExprCollector<'_> { } fn alloc_binding(&mut self, name: Name, mode: BindingAnnotation) -> BindingId { - self.body.bindings.alloc(Binding { + let binding = self.body.bindings.alloc(Binding { name, mode, definitions: SmallVec::new(), - owner: self.current_binding_owner, problems: None, - }) + }); + if let Some(owner) = self.current_binding_owner { + self.body.binding_owners.insert(binding, owner); + } + binding } fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs index 88380aa355d..cd6df0e6325 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs @@ -40,6 +40,7 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo }; format!("const {name} = ") } + DefWithBodyId::InTypeConstId(_) => format!("In type const = "), DefWithBodyId::VariantId(it) => { let src = it.parent.child_source(db); let variant = &src.value[it.local_id]; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index 6d18e3f56ca..04ec47f84ca 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -16,21 +16,22 @@ use crate::{ TraitAliasData, TraitData, TypeAliasData, }, generics::GenericParams, - hir::ExprId, import_map::ImportMap, item_tree::{AttrOwner, ItemTree}, lang_item::{LangItem, LangItemTarget, LangItems}, nameres::{diagnostics::DefDiagnostic, DefMap}, visibility::{self, Visibility}, - AnonymousConstId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, - EnumLoc, ExternBlockId, ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, - LocalEnumVariantId, LocalFieldId, Macro2Id, Macro2Loc, MacroRulesId, MacroRulesLoc, - ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitAliasId, - TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, VariantId, + AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId, + EnumId, EnumLoc, ExternBlockId, ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, + ImplLoc, InTypeConstId, InTypeConstLoc, LocalEnumVariantId, LocalFieldId, Macro2Id, Macro2Loc, + MacroRulesId, MacroRulesLoc, ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, + StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, + UnionLoc, VariantId, }; #[salsa::query_group(InternDatabaseStorage)] pub trait InternDatabase: SourceDatabase { + // region: items #[salsa::interned] fn intern_function(&self, loc: FunctionLoc) -> FunctionId; #[salsa::interned] @@ -54,15 +55,19 @@ pub trait InternDatabase: SourceDatabase { #[salsa::interned] fn intern_extern_block(&self, loc: ExternBlockLoc) -> ExternBlockId; #[salsa::interned] - fn intern_block(&self, loc: BlockLoc) -> BlockId; - #[salsa::interned] fn intern_macro2(&self, loc: Macro2Loc) -> Macro2Id; #[salsa::interned] fn intern_proc_macro(&self, loc: ProcMacroLoc) -> ProcMacroId; #[salsa::interned] fn intern_macro_rules(&self, loc: MacroRulesLoc) -> MacroRulesId; + // endregion: items + + #[salsa::interned] + fn intern_block(&self, loc: BlockLoc) -> BlockId; + #[salsa::interned] + fn intern_anonymous_const(&self, id: ConstBlockLoc) -> ConstBlockId; #[salsa::interned] - fn intern_anonymous_const(&self, id: (DefWithBodyId, ExprId)) -> AnonymousConstId; + fn intern_in_type_const(&self, id: InTypeConstLoc) -> InTypeConstId; } #[salsa::query_group(DefDatabaseStorage)] diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs index 34ed1e72f20..a588827c8d3 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs @@ -113,10 +113,10 @@ impl Expander { call_id: MacroCallId, error: Option<ExpandError>, ) -> ExpandResult<Option<InFile<Parse<SyntaxNode>>>> { - let file_id = call_id.as_file(); - let ExpandResult { value, err } = db.parse_or_expand_with_err(file_id); + let macro_file = call_id.as_macro_file(); + let ExpandResult { value, err } = db.parse_macro_expansion(macro_file); - ExpandResult { value: Some(InFile::new(file_id, value)), err: error.or(err) } + ExpandResult { value: Some(InFile::new(macro_file.into(), value.0)), err: error.or(err) } } pub fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { @@ -155,7 +155,7 @@ impl Expander { } pub(crate) fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option<Path> { - let ctx = LowerCtx::with_hygiene(db, &self.cfg_expander.hygiene); + let ctx = LowerCtx::new(db, &self.cfg_expander.hygiene, self.current_file_id); Path::from_src(path, &ctx) } @@ -179,8 +179,8 @@ impl Expander { } else if self.recursion_limit.check(self.recursion_depth as usize + 1).is_err() { self.recursion_depth = u32::MAX; cov_mark::hit!(your_stack_belongs_to_me); - return ExpandResult::only_err(ExpandError::Other( - "reached recursion limit during macro expansion".into(), + return ExpandResult::only_err(ExpandError::other( + "reached recursion limit during macro expansion", )); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs index e8cc2eab461..8c49ae1c4af 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs @@ -81,7 +81,7 @@ fn find_path_inner( } let def_map = from.def_map(db); - let crate_root = def_map.crate_root(); + let crate_root = def_map.crate_root().into(); // - if the item is a module, jump straight to module search if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item { let mut visited_modules = FxHashSet::default(); @@ -374,7 +374,7 @@ fn calculate_best_path( } } if let Some(module) = item.module(db) { - if module.def_map(db).block_id().is_some() && prefixed.is_some() { + if module.containing_block().is_some() && prefixed.is_some() { cov_mark::hit!(prefixed_in_block_expression); prefixed = Some(PrefixKind::Plain); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs index 4ad8a7aa8eb..500e880061a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs @@ -26,7 +26,7 @@ use crate::{ builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}, path::{GenericArgs, Path}, type_ref::{Mutability, Rawness, TypeRef}, - AnonymousConstId, BlockId, + BlockId, ConstBlockId, }; pub use syntax::ast::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp}; @@ -181,7 +181,7 @@ pub enum Expr { statements: Box<[Statement]>, tail: Option<ExprId>, }, - Const(AnonymousConstId), + Const(ConstBlockId), Unsafe { id: Option<BlockId>, statements: Box<[Statement]>, @@ -501,25 +501,9 @@ pub struct Binding { pub name: Name, pub mode: BindingAnnotation, pub definitions: SmallVec<[PatId; 1]>, - /// Id of the closure/generator that owns this binding. If it is owned by the - /// top level expression, this field would be `None`. - pub owner: Option<ExprId>, pub problems: Option<BindingProblems>, } -impl Binding { - pub fn is_upvar(&self, relative_to: ExprId) -> bool { - match self.owner { - Some(x) => { - // We assign expression ids in a way that outer closures will receive - // a lower id - x.into_raw() < relative_to.into_raw() - } - None => true, - } - } -} - #[derive(Debug, Clone, Eq, PartialEq)] pub struct RecordFieldPat { pub name: Name, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs index 0573c9a6f8a..fa1f4933a26 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs @@ -118,7 +118,7 @@ pub enum TypeRef { Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability), // FIXME: for full const generics, the latter element (length) here is going to have to be an // expression that is further lowered later in hir_ty. - Array(Box<TypeRef>, ConstRefOrPath), + Array(Box<TypeRef>, ConstRef), Slice(Box<TypeRef>), /// A fn pointer. Last element of the vector is the return type. Fn(Vec<(Option<Name>, TypeRef)>, bool /*varargs*/, bool /*is_unsafe*/), @@ -186,11 +186,7 @@ impl TypeRef { TypeRef::RawPtr(Box::new(inner_ty), mutability) } ast::Type::ArrayType(inner) => { - // FIXME: This is a hack. We should probably reuse the machinery of - // `hir_def::body::lower` to lower this into an `Expr` and then evaluate it at the - // `hir_ty` level, which would allow knowing the type of: - // let v: [u8; 2 + 2] = [0u8; 4]; - let len = ConstRefOrPath::from_expr_opt(inner.expr()); + let len = ConstRef::from_const_arg(ctx, inner.const_arg()); TypeRef::Array(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())), len) } ast::Type::SliceType(inner) => { @@ -380,73 +376,84 @@ impl TypeBound { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ConstRefOrPath { - Scalar(ConstRef), +pub enum ConstRef { + Scalar(LiteralConstRef), Path(Name), + Complex(AstId<ast::ConstArg>), } -impl ConstRefOrPath { - pub(crate) fn from_expr_opt(expr: Option<ast::Expr>) -> Self { - match expr { - Some(x) => Self::from_expr(x), - None => Self::Scalar(ConstRef::Unknown), +impl ConstRef { + pub(crate) fn from_const_arg(lower_ctx: &LowerCtx<'_>, arg: Option<ast::ConstArg>) -> Self { + if let Some(arg) = arg { + let ast_id = lower_ctx.ast_id(&arg); + if let Some(expr) = arg.expr() { + return Self::from_expr(expr, ast_id); + } } + Self::Scalar(LiteralConstRef::Unknown) } pub fn display<'a>(&'a self, db: &'a dyn ExpandDatabase) -> impl fmt::Display + 'a { - struct Display<'a>(&'a dyn ExpandDatabase, &'a ConstRefOrPath); + struct Display<'a>(&'a dyn ExpandDatabase, &'a ConstRef); impl fmt::Display for Display<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.1 { - ConstRefOrPath::Scalar(s) => s.fmt(f), - ConstRefOrPath::Path(n) => n.display(self.0).fmt(f), + ConstRef::Scalar(s) => s.fmt(f), + ConstRef::Path(n) => n.display(self.0).fmt(f), + ConstRef::Complex(_) => f.write_str("{const}"), } } } Display(db, self) } - // FIXME: as per the comments on `TypeRef::Array`, this evaluation should not happen at this - // parse stage. - fn from_expr(expr: ast::Expr) -> Self { + // We special case literals and single identifiers, to speed up things. + fn from_expr(expr: ast::Expr, ast_id: Option<AstId<ast::ConstArg>>) -> Self { + fn is_path_ident(p: &ast::PathExpr) -> bool { + let Some(path) = p.path() else { + return false; + }; + if path.coloncolon_token().is_some() { + return false; + } + if let Some(s) = path.segment() { + if s.coloncolon_token().is_some() || s.generic_arg_list().is_some() { + return false; + } + } + true + } match expr { - ast::Expr::PathExpr(p) => { + ast::Expr::PathExpr(p) if is_path_ident(&p) => { match p.path().and_then(|x| x.segment()).and_then(|x| x.name_ref()) { Some(x) => Self::Path(x.as_name()), - None => Self::Scalar(ConstRef::Unknown), + None => Self::Scalar(LiteralConstRef::Unknown), } } - ast::Expr::PrefixExpr(prefix_expr) => match prefix_expr.op_kind() { - Some(ast::UnaryOp::Neg) => { - let unsigned = Self::from_expr_opt(prefix_expr.expr()); - // Add sign - match unsigned { - Self::Scalar(ConstRef::UInt(num)) => { - Self::Scalar(ConstRef::Int(-(num as i128))) - } - other => other, - } - } - _ => Self::from_expr_opt(prefix_expr.expr()), - }, ast::Expr::Literal(literal) => Self::Scalar(match literal.kind() { ast::LiteralKind::IntNumber(num) => { - num.value().map(ConstRef::UInt).unwrap_or(ConstRef::Unknown) + num.value().map(LiteralConstRef::UInt).unwrap_or(LiteralConstRef::Unknown) } ast::LiteralKind::Char(c) => { - c.value().map(ConstRef::Char).unwrap_or(ConstRef::Unknown) + c.value().map(LiteralConstRef::Char).unwrap_or(LiteralConstRef::Unknown) } - ast::LiteralKind::Bool(f) => ConstRef::Bool(f), - _ => ConstRef::Unknown, + ast::LiteralKind::Bool(f) => LiteralConstRef::Bool(f), + _ => LiteralConstRef::Unknown, }), - _ => Self::Scalar(ConstRef::Unknown), + _ => { + if let Some(ast_id) = ast_id { + Self::Complex(ast_id) + } else { + Self::Scalar(LiteralConstRef::Unknown) + } + } } } } -/// A concrete constant value +/// A literal constant value #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ConstRef { +pub enum LiteralConstRef { Int(i128), UInt(u128), Bool(bool), @@ -460,18 +467,20 @@ pub enum ConstRef { Unknown, } -impl ConstRef { +impl LiteralConstRef { pub fn builtin_type(&self) -> BuiltinType { match self { - ConstRef::UInt(_) | ConstRef::Unknown => BuiltinType::Uint(BuiltinUint::U128), - ConstRef::Int(_) => BuiltinType::Int(BuiltinInt::I128), - ConstRef::Char(_) => BuiltinType::Char, - ConstRef::Bool(_) => BuiltinType::Bool, + LiteralConstRef::UInt(_) | LiteralConstRef::Unknown => { + BuiltinType::Uint(BuiltinUint::U128) + } + LiteralConstRef::Int(_) => BuiltinType::Int(BuiltinInt::I128), + LiteralConstRef::Char(_) => BuiltinType::Char, + LiteralConstRef::Bool(_) => BuiltinType::Bool, } } } -impl From<Literal> for ConstRef { +impl From<Literal> for LiteralConstRef { fn from(literal: Literal) -> Self { match literal { Literal::Char(c) => Self::Char(c), @@ -483,14 +492,14 @@ impl From<Literal> for ConstRef { } } -impl std::fmt::Display for ConstRef { +impl std::fmt::Display for LiteralConstRef { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { match self { - ConstRef::Int(num) => num.fmt(f), - ConstRef::UInt(num) => num.fmt(f), - ConstRef::Bool(flag) => flag.fmt(f), - ConstRef::Char(c) => write!(f, "'{c}'"), - ConstRef::Unknown => f.write_char('_'), + LiteralConstRef::Int(num) => num.fmt(f), + LiteralConstRef::UInt(num) => num.fmt(f), + LiteralConstRef::Bool(flag) => flag.fmt(f), + LiteralConstRef::Char(c) => write!(f, "'{c}'"), + LiteralConstRef::Unknown => f.write_char('_'), } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs index 3ed321d189d..2001fb29a9e 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs @@ -334,10 +334,6 @@ impl ItemScope { ) } - pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, SmallVec<[MacroId; 1]>> { - self.legacy_macros.clone() - } - /// Marks everything that is not a procedural macro as private to `this_module`. pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) { self.types diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index 590ed64af5d..e74b71888c2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -101,7 +101,6 @@ pub struct ItemTree { top_level: SmallVec<[ModItem; 1]>, attrs: FxHashMap<AttrOwner, RawAttrs>, - // FIXME: Remove this indirection, an item tree is almost always non-empty? data: Option<Box<ItemTreeData>>, } @@ -718,7 +717,6 @@ pub struct Mod { pub enum ModKind { /// `mod m { ... }` Inline { items: Box<[ModItem]> }, - /// `mod m;` Outline, } @@ -892,10 +890,6 @@ impl ModItem { } } - pub fn downcast<N: ItemTreeNode>(self) -> Option<FileItemTreeId<N>> { - N::id_from_mod_item(self) - } - pub fn ast_id(&self, tree: &ItemTree) -> FileAstId<ast::Item> { match self { ModItem::Import(it) => tree[it.index].ast_id().upcast(), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index 9cd3dfd6f7c..9d8b57a0da9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -57,13 +57,12 @@ mod test_db; mod macro_expansion_tests; mod pretty; -use std::hash::{Hash, Hasher}; - -use base_db::{ - impl_intern_key, - salsa::{self, InternId}, - CrateId, ProcMacroKind, +use std::{ + hash::{Hash, Hasher}, + panic::{RefUnwindSafe, UnwindSafe}, }; + +use base_db::{impl_intern_key, salsa, CrateId, ProcMacroKind}; use hir_expand::{ ast_id_map::FileAstId, attrs::{Attr, AttrId, AttrInput}, @@ -71,7 +70,7 @@ use hir_expand::{ builtin_derive_macro::BuiltinDeriveExpander, builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander}, db::ExpandDatabase, - eager::expand_eager_macro, + eager::expand_eager_macro_input, hygiene::Hygiene, proc_macro::ProcMacroExpander, AstId, ExpandError, ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, @@ -89,11 +88,51 @@ use crate::{ builtin_type::BuiltinType, data::adt::VariantData, item_tree::{ - Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, MacroDef, MacroRules, ModItem, - Static, Struct, Trait, TraitAlias, TypeAlias, Union, + Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, MacroDef, MacroRules, Static, + Struct, Trait, TraitAlias, TypeAlias, Union, }, }; +/// A `ModuleId` that is always a crate's root module. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct CrateRootModuleId { + krate: CrateId, +} + +impl CrateRootModuleId { + pub fn def_map(&self, db: &dyn db::DefDatabase) -> Arc<DefMap> { + db.crate_def_map(self.krate) + } + + pub fn krate(self) -> CrateId { + self.krate + } +} + +impl From<CrateRootModuleId> for ModuleId { + fn from(CrateRootModuleId { krate }: CrateRootModuleId) -> Self { + ModuleId { krate, block: None, local_id: DefMap::ROOT } + } +} + +impl From<CrateRootModuleId> for ModuleDefId { + fn from(value: CrateRootModuleId) -> Self { + ModuleDefId::ModuleId(value.into()) + } +} + +impl TryFrom<ModuleId> for CrateRootModuleId { + type Error = (); + + fn try_from(ModuleId { krate, block, local_id }: ModuleId) -> Result<Self, Self::Error> { + if block.is_none() && local_id == DefMap::ROOT { + Ok(CrateRootModuleId { krate }) + } else { + Err(()) + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ModuleId { krate: CrateId, @@ -315,8 +354,7 @@ impl_intern!(MacroRulesId, MacroRulesLoc, intern_macro_rules, lookup_intern_macr pub struct ProcMacroId(salsa::InternId); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ProcMacroLoc { - // FIXME: this should be a crate? or just a crate-root module - pub container: ModuleId, + pub container: CrateRootModuleId, pub id: ItemTreeId<Function>, pub expander: ProcMacroExpander, pub kind: ProcMacroKind, @@ -476,29 +514,199 @@ impl_from!( for ModuleDefId ); -// FIXME: make this a DefWithBodyId +/// Id of the anonymous const block expression and patterns. This is very similar to `ClosureId` and +/// shouldn't be a `DefWithBodyId` since its type inference is dependent on its parent. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] -pub struct AnonymousConstId(InternId); -impl_intern_key!(AnonymousConstId); +pub struct ConstBlockId(salsa::InternId); +impl_intern!(ConstBlockId, ConstBlockLoc, intern_anonymous_const, lookup_intern_anonymous_const); + +#[derive(Debug, Hash, PartialEq, Eq, Clone)] +pub struct ConstBlockLoc { + /// The parent of the anonymous const block. + pub parent: DefWithBodyId, + /// The root expression of this const block in the parent body. + pub root: hir::ExprId, +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub enum TypeOwnerId { + FunctionId(FunctionId), + StaticId(StaticId), + ConstId(ConstId), + InTypeConstId(InTypeConstId), + AdtId(AdtId), + TraitId(TraitId), + TraitAliasId(TraitAliasId), + TypeAliasId(TypeAliasId), + ImplId(ImplId), + EnumVariantId(EnumVariantId), + // FIXME(const-generic-body): ModuleId should not be a type owner. This needs to be fixed to make `TypeOwnerId` actually + // useful for assigning ids to in type consts. + ModuleId(ModuleId), +} + +impl TypeOwnerId { + fn as_generic_def_id(self) -> Option<GenericDefId> { + Some(match self { + TypeOwnerId::FunctionId(x) => GenericDefId::FunctionId(x), + TypeOwnerId::ConstId(x) => GenericDefId::ConstId(x), + TypeOwnerId::AdtId(x) => GenericDefId::AdtId(x), + TypeOwnerId::TraitId(x) => GenericDefId::TraitId(x), + TypeOwnerId::TraitAliasId(x) => GenericDefId::TraitAliasId(x), + TypeOwnerId::TypeAliasId(x) => GenericDefId::TypeAliasId(x), + TypeOwnerId::ImplId(x) => GenericDefId::ImplId(x), + TypeOwnerId::EnumVariantId(x) => GenericDefId::EnumVariantId(x), + TypeOwnerId::InTypeConstId(_) | TypeOwnerId::ModuleId(_) | TypeOwnerId::StaticId(_) => { + return None + } + }) + } +} + +impl_from!( + FunctionId, + StaticId, + ConstId, + InTypeConstId, + AdtId, + TraitId, + TraitAliasId, + TypeAliasId, + ImplId, + EnumVariantId, + ModuleId + for TypeOwnerId +); + +// Every `DefWithBodyId` is a type owner, since bodies can contain type (e.g. `{ let x: Type = _; }`) +impl From<DefWithBodyId> for TypeOwnerId { + fn from(value: DefWithBodyId) -> Self { + match value { + DefWithBodyId::FunctionId(x) => x.into(), + DefWithBodyId::StaticId(x) => x.into(), + DefWithBodyId::ConstId(x) => x.into(), + DefWithBodyId::InTypeConstId(x) => x.into(), + DefWithBodyId::VariantId(x) => x.into(), + } + } +} + +impl From<GenericDefId> for TypeOwnerId { + fn from(value: GenericDefId) -> Self { + match value { + GenericDefId::FunctionId(x) => x.into(), + GenericDefId::AdtId(x) => x.into(), + GenericDefId::TraitId(x) => x.into(), + GenericDefId::TraitAliasId(x) => x.into(), + GenericDefId::TypeAliasId(x) => x.into(), + GenericDefId::ImplId(x) => x.into(), + GenericDefId::EnumVariantId(x) => x.into(), + GenericDefId::ConstId(x) => x.into(), + } + } +} + +// FIXME: This should not be a thing +/// A thing that we want to store in interned ids, but we don't know its type in `hir-def`. This is +/// currently only used in `InTypeConstId` for storing the type (which has type `Ty` defined in +/// the `hir-ty` crate) of the constant in its id, which is a temporary hack so we may want +/// to remove this after removing that. +pub trait OpaqueInternableThing: + std::any::Any + std::fmt::Debug + Sync + Send + UnwindSafe + RefUnwindSafe +{ + fn as_any(&self) -> &dyn std::any::Any; + fn box_any(&self) -> Box<dyn std::any::Any>; + fn dyn_hash(&self, state: &mut dyn Hasher); + fn dyn_eq(&self, other: &dyn OpaqueInternableThing) -> bool; + fn dyn_clone(&self) -> Box<dyn OpaqueInternableThing>; +} + +impl Hash for dyn OpaqueInternableThing { + fn hash<H: Hasher>(&self, state: &mut H) { + self.dyn_hash(state); + } +} + +impl PartialEq for dyn OpaqueInternableThing { + fn eq(&self, other: &Self) -> bool { + self.dyn_eq(other) + } +} + +impl Eq for dyn OpaqueInternableThing {} + +impl Clone for Box<dyn OpaqueInternableThing> { + fn clone(&self) -> Self { + self.dyn_clone() + } +} + +// FIXME(const-generic-body): Use an stable id for in type consts. +// +// The current id uses `AstId<ast::ConstArg>` which will be changed by every change in the code. Ideally +// we should use an id which is relative to the type owner, so that every change will only invalidate the +// id if it happens inside of the type owner. +// +// The solution probably is to have some query on `TypeOwnerId` to traverse its constant children and store +// their `AstId` in a list (vector or arena), and use the index of that list in the id here. That query probably +// needs name resolution, and might go far and handles the whole path lowering or type lowering for a `TypeOwnerId`. +// +// Whatever path the solution takes, it should answer 3 questions at the same time: +// * Is the id stable enough? +// * How to find a constant id using an ast node / position in the source code? This is needed when we want to +// provide ide functionalities inside an in type const (which we currently don't support) e.g. go to definition +// for a local defined there. A complex id might have some trouble in this reverse mapping. +// * How to find the return type of a constant using its id? We have this data when we are doing type lowering +// and the name of the struct that contains this constant is resolved, so a query that only traverses the +// type owner by its syntax tree might have a hard time here. + +/// A constant in a type as a substitution for const generics (like `Foo<{ 2 + 2 }>`) or as an array +/// length (like `[u8; 2 + 2]`). These constants are body owner and are a variant of `DefWithBodyId`. These +/// are not called `AnonymousConstId` to prevent confusion with [`ConstBlockId`]. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub struct InTypeConstId(salsa::InternId); +impl_intern!(InTypeConstId, InTypeConstLoc, intern_in_type_const, lookup_intern_in_type_const); + +#[derive(Debug, Hash, Eq, Clone)] +pub struct InTypeConstLoc { + pub id: AstId<ast::ConstArg>, + /// The thing this const arg appears in + pub owner: TypeOwnerId, + pub thing: Box<dyn OpaqueInternableThing>, +} + +impl PartialEq for InTypeConstLoc { + fn eq(&self, other: &Self) -> bool { + self.id == other.id && self.owner == other.owner && &*self.thing == &*other.thing + } +} + +impl InTypeConstId { + pub fn source(&self, db: &dyn db::DefDatabase) -> ast::ConstArg { + let src = self.lookup(db).id; + let file_id = src.file_id; + let root = &db.parse_or_expand(file_id); + db.ast_id_map(file_id).get(src.value).to_node(root) + } +} /// A constant, which might appears as a const item, an annonymous const block in expressions /// or patterns, or as a constant in types with const generics. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum GeneralConstId { ConstId(ConstId), - AnonymousConstId(AnonymousConstId), + ConstBlockId(ConstBlockId), + InTypeConstId(InTypeConstId), } -impl_from!(ConstId, AnonymousConstId for GeneralConstId); +impl_from!(ConstId, ConstBlockId, InTypeConstId for GeneralConstId); impl GeneralConstId { pub fn generic_def(self, db: &dyn db::DefDatabase) -> Option<GenericDefId> { match self { - GeneralConstId::ConstId(x) => Some(x.into()), - GeneralConstId::AnonymousConstId(x) => { - let (parent, _) = db.lookup_intern_anonymous_const(x); - parent.as_generic_def_id() - } + GeneralConstId::ConstId(it) => Some(it.into()), + GeneralConstId::ConstBlockId(it) => it.lookup(db).parent.as_generic_def_id(), + GeneralConstId::InTypeConstId(it) => it.lookup(db).owner.as_generic_def_id(), } } @@ -511,7 +719,8 @@ impl GeneralConstId { .and_then(|x| x.as_str()) .unwrap_or("_") .to_owned(), - GeneralConstId::AnonymousConstId(id) => format!("{{anonymous const {id:?}}}"), + GeneralConstId::ConstBlockId(id) => format!("{{anonymous const {id:?}}}"), + GeneralConstId::InTypeConstId(id) => format!("{{in type const {id:?}}}"), } } } @@ -522,10 +731,11 @@ pub enum DefWithBodyId { FunctionId(FunctionId), StaticId(StaticId), ConstId(ConstId), + InTypeConstId(InTypeConstId), VariantId(EnumVariantId), } -impl_from!(FunctionId, ConstId, StaticId for DefWithBodyId); +impl_from!(FunctionId, ConstId, StaticId, InTypeConstId for DefWithBodyId); impl From<EnumVariantId> for DefWithBodyId { fn from(id: EnumVariantId) -> Self { @@ -540,6 +750,9 @@ impl DefWithBodyId { DefWithBodyId::StaticId(_) => None, DefWithBodyId::ConstId(c) => Some(c.into()), DefWithBodyId::VariantId(c) => Some(c.into()), + // FIXME: stable rust doesn't allow generics in constants, but we should + // use `TypeOwnerId::as_generic_def_id` when it does. + DefWithBodyId::InTypeConstId(_) => None, } } } @@ -729,29 +942,37 @@ impl HasModule for MacroId { match self { MacroId::MacroRulesId(it) => it.lookup(db).container, MacroId::Macro2Id(it) => it.lookup(db).container, - MacroId::ProcMacroId(it) => it.lookup(db).container, + MacroId::ProcMacroId(it) => it.lookup(db).container.into(), } } } -impl HasModule for DefWithBodyId { +impl HasModule for TypeOwnerId { fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { match self { - DefWithBodyId::FunctionId(it) => it.lookup(db).module(db), - DefWithBodyId::StaticId(it) => it.lookup(db).module(db), - DefWithBodyId::ConstId(it) => it.lookup(db).module(db), - DefWithBodyId::VariantId(it) => it.parent.lookup(db).container, + TypeOwnerId::FunctionId(x) => x.lookup(db).module(db), + TypeOwnerId::StaticId(x) => x.lookup(db).module(db), + TypeOwnerId::ConstId(x) => x.lookup(db).module(db), + TypeOwnerId::InTypeConstId(x) => x.lookup(db).owner.module(db), + TypeOwnerId::AdtId(x) => x.module(db), + TypeOwnerId::TraitId(x) => x.lookup(db).container, + TypeOwnerId::TraitAliasId(x) => x.lookup(db).container, + TypeOwnerId::TypeAliasId(x) => x.lookup(db).module(db), + TypeOwnerId::ImplId(x) => x.lookup(db).container, + TypeOwnerId::EnumVariantId(x) => x.parent.lookup(db).container, + TypeOwnerId::ModuleId(x) => *x, } } } -impl DefWithBodyId { - pub fn as_mod_item(self, db: &dyn db::DefDatabase) -> ModItem { +impl HasModule for DefWithBodyId { + fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { match self { - DefWithBodyId::FunctionId(it) => it.lookup(db).id.value.into(), - DefWithBodyId::StaticId(it) => it.lookup(db).id.value.into(), - DefWithBodyId::ConstId(it) => it.lookup(db).id.value.into(), - DefWithBodyId::VariantId(it) => it.parent.lookup(db).id.value.into(), + DefWithBodyId::FunctionId(it) => it.lookup(db).module(db), + DefWithBodyId::StaticId(it) => it.lookup(db).module(db), + DefWithBodyId::ConstId(it) => it.lookup(db).module(db), + DefWithBodyId::VariantId(it) => it.parent.lookup(db).container, + DefWithBodyId::InTypeConstId(it) => it.lookup(db).owner.module(db), } } } @@ -865,7 +1086,7 @@ impl AsMacroCall for InFile<&ast::MacroCall> { let path = self.value.path().and_then(|path| path::ModPath::from_src(db, path, &h)); let Some(path) = path else { - return Ok(ExpandResult::only_err(ExpandError::Other("malformed macro invocation".into()))); + return Ok(ExpandResult::only_err(ExpandError::other("malformed macro invocation"))); }; macro_call_as_call_id_( @@ -913,7 +1134,7 @@ fn macro_call_as_call_id_( let res = if let MacroDefKind::BuiltInEager(..) = def.kind { let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db)); - expand_eager_macro(db, krate, macro_call, def, &resolver)? + expand_eager_macro_input(db, krate, macro_call, def, &resolver)? } else { ExpandResult { value: Some(def.as_lazy_macro( @@ -1028,13 +1249,13 @@ fn attr_macro_as_call_id( def: MacroDefId, ) -> MacroCallId { let arg = match macro_attr.input.as_deref() { - Some(AttrInput::TokenTree(tt, map)) => ( + Some(AttrInput::TokenTree(tt)) => ( { - let mut tt = tt.clone(); + let mut tt = tt.0.clone(); tt.delimiter = tt::Delimiter::UNSPECIFIED; tt }, - map.clone(), + tt.1.clone(), ), _ => (tt::Subtree::empty(), Default::default()), }; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs index 80474bc154d..f41f9719043 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs @@ -115,6 +115,66 @@ impl <A: core::clone::Clone, B: core::clone::Clone, > core::clone::Clone for Com } #[test] +fn test_clone_expand_with_associated_types() { + check( + r#" +//- minicore: derive, clone +trait Trait { + type InWc; + type InFieldQualified; + type InFieldShorthand; + type InGenericArg; +} +trait Marker {} +struct Vec<T>(T); + +#[derive(Clone)] +struct Foo<T: Trait> +where + <T as Trait>::InWc: Marker, +{ + qualified: <T as Trait>::InFieldQualified, + shorthand: T::InFieldShorthand, + generic: Vec<T::InGenericArg>, +} +"#, + expect![[r#" +trait Trait { + type InWc; + type InFieldQualified; + type InFieldShorthand; + type InGenericArg; +} +trait Marker {} +struct Vec<T>(T); + +#[derive(Clone)] +struct Foo<T: Trait> +where + <T as Trait>::InWc: Marker, +{ + qualified: <T as Trait>::InFieldQualified, + shorthand: T::InFieldShorthand, + generic: Vec<T::InGenericArg>, +} + +impl <T: core::clone::Clone, > core::clone::Clone for Foo<T, > where T: Trait, T::InFieldShorthand: core::clone::Clone, T::InGenericArg: core::clone::Clone, { + fn clone(&self ) -> Self { + match self { + Foo { + qualified: qualified, shorthand: shorthand, generic: generic, + } + =>Foo { + qualified: qualified.clone(), shorthand: shorthand.clone(), generic: generic.clone(), + } + , + } + } +}"#]], + ); +} + +#[test] fn test_clone_expand_with_const_generics() { check( r#" @@ -336,18 +396,18 @@ enum Command { } impl < > core::hash::Hash for Command< > where { - fn hash<H: core::hash::Hasher>(&self , state: &mut H) { - core::mem::discriminant(self ).hash(state); + fn hash<H: core::hash::Hasher>(&self , ra_expand_state: &mut H) { + core::mem::discriminant(self ).hash(ra_expand_state); match self { Command::Move { x: x, y: y, } => { - x.hash(state); - y.hash(state); + x.hash(ra_expand_state); + y.hash(ra_expand_state); } , Command::Do(f0, )=> { - f0.hash(state); + f0.hash(ra_expand_state); } , Command::Jump=> {} , diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index 977f300636f..07d9baa5897 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -79,7 +79,7 @@ fn main() { env!("TEST_ENV_VAR"); } #[rustc_builtin_macro] macro_rules! env {() => {}} -fn main() { "__RA_UNIMPLEMENTED__"; } +fn main() { "UNRESOLVED_ENV_VAR"; } "##]], ); } @@ -208,6 +208,44 @@ fn main() { } #[test] +fn regression_15002() { + check( + r#" +#[rustc_builtin_macro] +macro_rules! format_args { + ($fmt:expr) => ({ /* compiler built-in */ }); + ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) +} + +fn main() { + format_args!(x = 2); + format_args!(x =); + format_args!(x =, x = 2); + format_args!("{}", x =); + format_args!(=, "{}", x =); + format_args!(x = 2, "{}", 5); +} +"#, + expect![[r##" +#[rustc_builtin_macro] +macro_rules! format_args { + ($fmt:expr) => ({ /* compiler built-in */ }); + ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) +} + +fn main() { + /* error: no rule matches input tokens */; + /* error: no rule matches input tokens */; + /* error: no rule matches input tokens */; + /* error: no rule matches input tokens */::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::Argument::new(&(), ::core::fmt::Display::fmt), ]); + /* error: no rule matches input tokens */; + ::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::Argument::new(&(5), ::core::fmt::Display::fmt), ]); +} +"##]], + ); +} + +#[test] fn test_format_args_expand_with_comma_exprs() { check( r#" @@ -404,10 +442,6 @@ macro_rules! surprise { () => { "s" }; } -macro_rules! stuff { - ($string:expr) => { concat!($string) }; -} - fn main() { concat!(surprise!()); } "##, expect![[r##" @@ -418,10 +452,6 @@ macro_rules! surprise { () => { "s" }; } -macro_rules! stuff { - ($string:expr) => { concat!($string) }; -} - fn main() { "s"; } "##]], ); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs index 9b520bc3030..0ab1bd8490c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs @@ -77,8 +77,8 @@ use crate::{ path::ModPath, per_ns::PerNs, visibility::Visibility, - AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, - ProcMacroId, + AstId, BlockId, BlockLoc, CrateRootModuleId, FunctionId, LocalModuleId, Lookup, MacroExpander, + MacroId, ModuleId, ProcMacroId, }; /// Contains the results of (early) name resolution. @@ -93,7 +93,10 @@ use crate::{ #[derive(Debug, PartialEq, Eq)] pub struct DefMap { _c: Count<Self>, + /// When this is a block def map, this will hold the block id of the the block and module that + /// contains this block. block: Option<BlockInfo>, + /// The modules and their data declared in this crate. modules: Arena<ModuleData>, krate: CrateId, /// The prelude module for this crate. This either comes from an import @@ -111,15 +114,18 @@ pub struct DefMap { /// attributes. derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<(Name, MacroId, MacroCallId)>>, + /// The diagnostics that need to be emitted for this crate. diagnostics: Vec<DefDiagnostic>, + /// The crate data that is shared between a crate's def map and all its block def maps. data: Arc<DefMapCrateData>, } /// Data that belongs to a crate which is shared between a crate's def map and all its block def maps. #[derive(Clone, Debug, PartialEq, Eq)] struct DefMapCrateData { - extern_prelude: FxHashMap<Name, ModuleId>, + /// The extern prelude which contains all root modules of external crates that are in scope. + extern_prelude: FxHashMap<Name, CrateRootModuleId>, /// Side table for resolving derive helpers. exported_derives: FxHashMap<MacroDefId, Box<[Name]>>, @@ -279,6 +285,7 @@ pub struct ModuleData { } impl DefMap { + /// The module id of a crate or block root. pub const ROOT: LocalModuleId = LocalModuleId::from_raw(la_arena::RawIdx::from_u32(0)); pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<DefMap> { @@ -419,11 +426,11 @@ impl DefMap { } pub(crate) fn extern_prelude(&self) -> impl Iterator<Item = (&Name, ModuleId)> + '_ { - self.data.extern_prelude.iter().map(|(name, def)| (name, *def)) + self.data.extern_prelude.iter().map(|(name, &def)| (name, def.into())) } pub(crate) fn macro_use_prelude(&self) -> impl Iterator<Item = (&Name, MacroId)> + '_ { - self.macro_use_prelude.iter().map(|(name, def)| (name, *def)) + self.macro_use_prelude.iter().map(|(name, &def)| (name, def)) } pub fn module_id(&self, local_id: LocalModuleId) -> ModuleId { @@ -431,8 +438,8 @@ impl DefMap { ModuleId { krate: self.krate, local_id, block } } - pub(crate) fn crate_root(&self) -> ModuleId { - ModuleId { krate: self.krate, block: None, local_id: DefMap::ROOT } + pub fn crate_root(&self) -> CrateRootModuleId { + CrateRootModuleId { krate: self.krate } } pub(crate) fn resolve_path( @@ -476,7 +483,7 @@ impl DefMap { /// /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns /// `None`, iteration continues. - pub fn with_ancestor_maps<T>( + pub(crate) fn with_ancestor_maps<T>( &self, db: &dyn DefDatabase, local_mod: LocalModuleId, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 06542b4b1e9..62fb3c7882c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -3,7 +3,7 @@ //! `DefCollector::collect` contains the fixed-point iteration loop which //! resolves imports and expands macros. -use std::{iter, mem}; +use std::{cmp::Ordering, iter, mem}; use base_db::{CrateId, Dependency, Edition, FileId}; use cfg::{CfgExpr, CfgOptions}; @@ -51,11 +51,11 @@ use crate::{ per_ns::PerNs, tt, visibility::{RawVisibility, Visibility}, - AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, ExternBlockLoc, FunctionId, - FunctionLoc, ImplLoc, Intern, ItemContainerId, LocalModuleId, Macro2Id, Macro2Loc, - MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, ModuleDefId, ModuleId, ProcMacroId, - ProcMacroLoc, StaticLoc, StructLoc, TraitAliasLoc, TraitLoc, TypeAliasLoc, UnionLoc, - UnresolvedMacro, + AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantId, + ExternBlockLoc, FunctionId, FunctionLoc, ImplLoc, Intern, ItemContainerId, LocalModuleId, + Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, ModuleDefId, + ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, StructLoc, TraitAliasLoc, TraitLoc, + TypeAliasLoc, UnionLoc, UnresolvedMacro, }; static GLOB_RECURSION_LIMIT: Limit = Limit::new(100); @@ -274,8 +274,6 @@ impl DefCollector<'_> { let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id; let item_tree = self.db.file_item_tree(file_id.into()); - let module_id = DefMap::ROOT; - let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate); let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap(); @@ -285,10 +283,9 @@ impl DefCollector<'_> { for (name, dep) in &self.deps { if dep.is_prelude() { - crate_data.extern_prelude.insert( - name.clone(), - ModuleId { krate: dep.crate_id, block: None, local_id: DefMap::ROOT }, - ); + crate_data + .extern_prelude + .insert(name.clone(), CrateRootModuleId { krate: dep.crate_id }); } } @@ -374,7 +371,7 @@ impl DefCollector<'_> { ModCollector { def_collector: self, macro_depth: 0, - module_id, + module_id: DefMap::ROOT, tree_id: TreeId::new(file_id.into(), None), item_tree: &item_tree, mod_dir: ModDir::root(), @@ -384,8 +381,6 @@ impl DefCollector<'_> { fn seed_with_inner(&mut self, tree_id: TreeId) { let item_tree = tree_id.item_tree(self.db); - let module_id = DefMap::ROOT; - let is_cfg_enabled = item_tree .top_level_attrs(self.db, self.def_map.krate) .cfg() @@ -394,7 +389,7 @@ impl DefCollector<'_> { ModCollector { def_collector: self, macro_depth: 0, - module_id, + module_id: DefMap::ROOT, tree_id, item_tree: &item_tree, mod_dir: ModDir::root(), @@ -604,8 +599,6 @@ impl DefCollector<'_> { if self.def_map.block.is_some() { return; } - let crate_root = self.def_map.module_id(DefMap::ROOT); - let kind = def.kind.to_basedb_kind(); let (expander, kind) = match self.proc_macros.as_ref().map(|it| it.iter().find(|(n, _)| n == &def.name)) { @@ -614,7 +607,8 @@ impl DefCollector<'_> { }; let proc_macro_id = - ProcMacroLoc { container: crate_root, id, expander, kind }.intern(self.db); + ProcMacroLoc { container: self.def_map.crate_root(), id, expander, kind } + .intern(self.db); self.define_proc_macro(def.name.clone(), proc_macro_id); let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap(); if let ProcMacroKind::CustomDerive { helpers } = def.kind { @@ -831,16 +825,12 @@ impl DefCollector<'_> { } } - fn resolve_extern_crate(&self, name: &Name) -> Option<ModuleId> { + fn resolve_extern_crate(&self, name: &Name) -> Option<CrateRootModuleId> { if *name == name!(self) { cov_mark::hit!(extern_crate_self_as); Some(self.def_map.crate_root()) } else { - self.deps.get(name).map(|dep| ModuleId { - krate: dep.crate_id, - block: None, - local_id: DefMap::ROOT, - }) + self.deps.get(name).map(|dep| CrateRootModuleId { krate: dep.crate_id }) } } @@ -883,10 +873,12 @@ impl DefCollector<'_> { { if let (Some(ModuleDefId::ModuleId(def)), Some(name)) = (def.take_types(), name) { - Arc::get_mut(&mut self.def_map.data) - .unwrap() - .extern_prelude - .insert(name.clone(), def); + if let Ok(def) = def.try_into() { + Arc::get_mut(&mut self.def_map.data) + .unwrap() + .extern_prelude + .insert(name.clone(), def); + } } } @@ -1791,13 +1783,11 @@ impl ModCollector<'_, '_> { let target_crate = match self.def_collector.resolve_extern_crate(&self.item_tree[extern_crate].name) { - Some(m) => { - if m == self.def_collector.def_map.module_id(self.module_id) { - cov_mark::hit!(ignore_macro_use_extern_crate_self); - return; - } - m.krate + Some(m) if m.krate == self.def_collector.def_map.krate => { + cov_mark::hit!(ignore_macro_use_extern_crate_self); + return; } + Some(m) => m.krate, None => return, }; @@ -1938,9 +1928,13 @@ impl ModCollector<'_, '_> { let modules = &mut def_map.modules; let res = modules.alloc(ModuleData::new(origin, vis)); modules[res].parent = Some(self.module_id); - for (name, mac) in modules[self.module_id].scope.collect_legacy_macros() { - for &mac in &mac { - modules[res].scope.define_legacy_macro(name.clone(), mac); + + if let Some((target, source)) = Self::borrow_modules(modules.as_mut(), res, self.module_id) + { + for (name, macs) in source.scope.legacy_macros() { + for &mac in macs { + target.scope.define_legacy_macro(name.clone(), mac); + } } } modules[self.module_id].children.insert(name.clone(), res); @@ -2236,14 +2230,40 @@ impl ModCollector<'_, '_> { } fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) { - let macros = self.def_collector.def_map[module_id].scope.collect_legacy_macros(); - for (name, macs) in macros { + let Some((source, target)) = Self::borrow_modules(self.def_collector.def_map.modules.as_mut(), module_id, self.module_id) else { + return + }; + + for (name, macs) in source.scope.legacy_macros() { macs.last().map(|&mac| { - self.def_collector.define_legacy_macro(self.module_id, name.clone(), mac) + target.scope.define_legacy_macro(name.clone(), mac); }); } } + /// Mutably borrow two modules at once, retu + fn borrow_modules( + modules: &mut [ModuleData], + a: LocalModuleId, + b: LocalModuleId, + ) -> Option<(&mut ModuleData, &mut ModuleData)> { + let a = a.into_raw().into_u32() as usize; + let b = b.into_raw().into_u32() as usize; + + let (a, b) = match a.cmp(&b) { + Ordering::Equal => return None, + Ordering::Less => { + let (prefix, b) = modules.split_at_mut(b); + (&mut prefix[a], &mut b[0]) + } + Ordering::Greater => { + let (prefix, a) = modules.split_at_mut(a); + (&mut a[0], &mut prefix[b]) + } + }; + Some((a, b)) + } + fn is_cfg_enabled(&self, cfg: &CfgExpr) -> bool { self.def_collector.cfg_options.check(cfg) != Some(false) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/path.rs index b9b80825497..ff4ae69546c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs @@ -9,7 +9,7 @@ use std::{ use crate::{ lang_item::LangItemTarget, lower::LowerCtx, - type_ref::{ConstRefOrPath, LifetimeRef, TypeBound, TypeRef}, + type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef}, }; use hir_expand::name::Name; use intern::Interned; @@ -90,7 +90,7 @@ pub struct AssociatedTypeBinding { pub enum GenericArg { Type(TypeRef), Lifetime(LifetimeRef), - Const(ConstRefOrPath), + Const(ConstRef), } impl Path { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs index 26d2706175c..1cb17ff0d26 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs @@ -2,7 +2,7 @@ use std::iter; -use crate::{lower::LowerCtx, type_ref::ConstRefOrPath}; +use crate::{lower::LowerCtx, type_ref::ConstRef}; use either::Either; use hir_expand::name::{name, AsName}; @@ -217,7 +217,7 @@ pub(super) fn lower_generic_args( } } ast::GenericArg::ConstArg(arg) => { - let arg = ConstRefOrPath::from_expr_opt(arg.expr()); + let arg = ConstRef::from_const_arg(lower_ctx, Some(arg)); args.push(GenericArg::Const(arg)) } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index 06f5b2526a4..0d6f55411c1 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -21,11 +21,11 @@ use crate::{ path::{ModPath, Path, PathKind}, per_ns::PerNs, visibility::{RawVisibility, Visibility}, - AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, - FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, - LocalModuleId, Lookup, Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, - StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, - VariantId, + AdtId, AssocItemId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, + EnumVariantId, ExternBlockId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, + ItemContainerId, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, MacroId, MacroRulesId, + ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, + TypeOrConstParamId, TypeOwnerId, TypeParamId, VariantId, }; #[derive(Debug, Clone)] @@ -946,6 +946,15 @@ impl HasResolver for ModuleId { } } +impl HasResolver for CrateRootModuleId { + fn resolver(self, db: &dyn DefDatabase) -> Resolver { + Resolver { + scopes: vec![], + module_scope: ModuleItemMap { def_map: self.def_map(db), module_id: DefMap::ROOT }, + } + } +} + impl HasResolver for TraitId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into()) @@ -1009,6 +1018,24 @@ impl HasResolver for ExternBlockId { } } +impl HasResolver for TypeOwnerId { + fn resolver(self, db: &dyn DefDatabase) -> Resolver { + match self { + TypeOwnerId::FunctionId(x) => x.resolver(db), + TypeOwnerId::StaticId(x) => x.resolver(db), + TypeOwnerId::ConstId(x) => x.resolver(db), + TypeOwnerId::InTypeConstId(x) => x.lookup(db).owner.resolver(db), + TypeOwnerId::AdtId(x) => x.resolver(db), + TypeOwnerId::TraitId(x) => x.resolver(db), + TypeOwnerId::TraitAliasId(x) => x.resolver(db), + TypeOwnerId::TypeAliasId(x) => x.resolver(db), + TypeOwnerId::ImplId(x) => x.resolver(db), + TypeOwnerId::EnumVariantId(x) => x.resolver(db), + TypeOwnerId::ModuleId(x) => x.resolver(db), + } + } +} + impl HasResolver for DefWithBodyId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { match self { @@ -1016,6 +1043,7 @@ impl HasResolver for DefWithBodyId { DefWithBodyId::FunctionId(f) => f.resolver(db), DefWithBodyId::StaticId(s) => s.resolver(db), DefWithBodyId::VariantId(v) => v.parent.resolver(db), + DefWithBodyId::InTypeConstId(c) => c.lookup(db).owner.resolver(db), } } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs b/src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs index 400442de94b..c2b0d5985e3 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs @@ -20,7 +20,7 @@ use syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; /// `AstId` points to an AST node in a specific file. pub struct FileAstId<N: AstNode> { raw: ErasedFileAstId, - _ty: PhantomData<fn() -> N>, + covariant: PhantomData<fn() -> N>, } impl<N: AstNode> Clone for FileAstId<N> { @@ -54,7 +54,7 @@ impl<N: AstNode> FileAstId<N> { where N: Into<M>, { - FileAstId { raw: self.raw, _ty: PhantomData } + FileAstId { raw: self.raw, covariant: PhantomData } } } @@ -98,6 +98,7 @@ impl AstIdMap { || ast::Variant::can_cast(kind) || ast::RecordField::can_cast(kind) || ast::TupleField::can_cast(kind) + || ast::ConstArg::can_cast(kind) { res.alloc(&it); true @@ -121,7 +122,7 @@ impl AstIdMap { pub fn ast_id<N: AstNode>(&self, item: &N) -> FileAstId<N> { let raw = self.erased_ast_id(item.syntax()); - FileAstId { raw, _ty: PhantomData } + FileAstId { raw, covariant: PhantomData } } pub fn get<N: AstNode>(&self, id: FileAstId<N>) -> AstPtr<N> { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs index 0c369a18bb9..4c918e55b92 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs @@ -192,14 +192,14 @@ pub enum AttrInput { /// `#[attr = "string"]` Literal(SmolStr), /// `#[attr(subtree)]` - TokenTree(tt::Subtree, mbe::TokenMap), + TokenTree(Box<(tt::Subtree, mbe::TokenMap)>), } impl fmt::Display for AttrInput { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { AttrInput::Literal(lit) => write!(f, " = \"{}\"", lit.escape_debug()), - AttrInput::TokenTree(subtree, _) => subtree.fmt(f), + AttrInput::TokenTree(tt) => tt.0.fmt(f), } } } @@ -220,7 +220,7 @@ impl Attr { Some(Interned::new(AttrInput::Literal(value))) } else if let Some(tt) = ast.token_tree() { let (tree, map) = syntax_node_to_token_tree(tt.syntax()); - Some(Interned::new(AttrInput::TokenTree(tree, map))) + Some(Interned::new(AttrInput::TokenTree(Box::new((tree, map))))) } else { None }; @@ -256,7 +256,7 @@ impl Attr { /// #[path(ident)] pub fn single_ident_value(&self) -> Option<&tt::Ident> { match self.input.as_deref()? { - AttrInput::TokenTree(subtree, _) => match &*subtree.token_trees { + AttrInput::TokenTree(tt) => match &*tt.0.token_trees { [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] => Some(ident), _ => None, }, @@ -267,7 +267,7 @@ impl Attr { /// #[path TokenTree] pub fn token_tree_value(&self) -> Option<&Subtree> { match self.input.as_deref()? { - AttrInput::TokenTree(subtree, _) => Some(subtree), + AttrInput::TokenTree(tt) => Some(&tt.0), _ => None, } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs index 54706943ac4..3d1e272b900 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs @@ -4,17 +4,16 @@ use ::tt::Ident; use base_db::{CrateOrigin, LangCrateOrigin}; use itertools::izip; use mbe::TokenMap; -use std::collections::HashSet; +use rustc_hash::FxHashSet; use stdx::never; use tracing::debug; -use crate::tt::{self, TokenId}; -use syntax::{ - ast::{ - self, AstNode, FieldList, HasAttrs, HasGenericParams, HasModuleItem, HasName, - HasTypeBounds, PathType, - }, - match_ast, +use crate::{ + name::{AsName, Name}, + tt::{self, TokenId}, +}; +use syntax::ast::{ + self, AstNode, FieldList, HasAttrs, HasGenericParams, HasModuleItem, HasName, HasTypeBounds, }; use crate::{db::ExpandDatabase, name, quote, ExpandError, ExpandResult, MacroCallId}; @@ -195,39 +194,52 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> { let (parsed, token_map) = mbe::token_tree_to_syntax_node(tt, mbe::TopEntryPoint::MacroItems); let macro_items = ast::MacroItems::cast(parsed.syntax_node()).ok_or_else(|| { debug!("derive node didn't parse"); - ExpandError::Other("invalid item definition".into()) + ExpandError::other("invalid item definition") })?; let item = macro_items.items().next().ok_or_else(|| { debug!("no module item parsed"); - ExpandError::Other("no item found".into()) + ExpandError::other("no item found") })?; - let node = item.syntax(); - let (name, params, shape) = match_ast! { - match node { - ast::Struct(it) => (it.name(), it.generic_param_list(), AdtShape::Struct(VariantShape::from(it.field_list(), &token_map)?)), - ast::Enum(it) => { - let default_variant = it.variant_list().into_iter().flat_map(|x| x.variants()).position(|x| x.attrs().any(|x| x.simple_name() == Some("default".into()))); - ( - it.name(), - it.generic_param_list(), - AdtShape::Enum { - default_variant, - variants: it.variant_list() - .into_iter() - .flat_map(|x| x.variants()) - .map(|x| Ok((name_to_token(&token_map,x.name())?, VariantShape::from(x.field_list(), &token_map)?))).collect::<Result<_, ExpandError>>()? - } - ) - }, - ast::Union(it) => (it.name(), it.generic_param_list(), AdtShape::Union), - _ => { - debug!("unexpected node is {:?}", node); - return Err(ExpandError::Other("expected struct, enum or union".into())) - }, + let adt = ast::Adt::cast(item.syntax().clone()).ok_or_else(|| { + debug!("expected adt, found: {:?}", item); + ExpandError::other("expected struct, enum or union") + })?; + let (name, generic_param_list, shape) = match &adt { + ast::Adt::Struct(it) => ( + it.name(), + it.generic_param_list(), + AdtShape::Struct(VariantShape::from(it.field_list(), &token_map)?), + ), + ast::Adt::Enum(it) => { + let default_variant = it + .variant_list() + .into_iter() + .flat_map(|x| x.variants()) + .position(|x| x.attrs().any(|x| x.simple_name() == Some("default".into()))); + ( + it.name(), + it.generic_param_list(), + AdtShape::Enum { + default_variant, + variants: it + .variant_list() + .into_iter() + .flat_map(|x| x.variants()) + .map(|x| { + Ok(( + name_to_token(&token_map, x.name())?, + VariantShape::from(x.field_list(), &token_map)?, + )) + }) + .collect::<Result<_, ExpandError>>()?, + }, + ) } + ast::Adt::Union(it) => (it.name(), it.generic_param_list(), AdtShape::Union), }; - let mut param_type_set: HashSet<String> = HashSet::new(); - let param_types = params + + let mut param_type_set: FxHashSet<Name> = FxHashSet::default(); + let param_types = generic_param_list .into_iter() .flat_map(|param_list| param_list.type_or_const_params()) .map(|param| { @@ -235,7 +247,7 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> { let this = param.name(); match this { Some(x) => { - param_type_set.insert(x.to_string()); + param_type_set.insert(x.as_name()); mbe::syntax_node_to_token_tree(x.syntax()).0 } None => tt::Subtree::empty(), @@ -259,37 +271,33 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> { (name, ty, bounds) }) .collect(); - let is_associated_type = |p: &PathType| { - if let Some(p) = p.path() { - if let Some(parent) = p.qualifier() { - if let Some(x) = parent.segment() { - if let Some(x) = x.path_type() { - if let Some(x) = x.path() { - if let Some(pname) = x.as_single_name_ref() { - if param_type_set.contains(&pname.to_string()) { - // <T as Trait>::Assoc - return true; - } - } - } - } - } - if let Some(pname) = parent.as_single_name_ref() { - if param_type_set.contains(&pname.to_string()) { - // T::Assoc - return true; - } - } - } - } - false + + // For a generic parameter `T`, when shorthand associated type `T::Assoc` appears in field + // types (of any variant for enums), we generate trait bound for it. It sounds reasonable to + // also generate trait bound for qualified associated type `<T as Trait>::Assoc`, but rustc + // does not do that for some unknown reason. + // + // See the analogous function in rustc [find_type_parameters()] and rust-lang/rust#50730. + // [find_type_parameters()]: https://github.com/rust-lang/rust/blob/1.70.0/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs#L378 + + // It's cumbersome to deal with the distinct structures of ADTs, so let's just get untyped + // `SyntaxNode` that contains fields and look for descendant `ast::PathType`s. Of note is that + // we should not inspect `ast::PathType`s in parameter bounds and where clauses. + let field_list = match adt { + ast::Adt::Enum(it) => it.variant_list().map(|list| list.syntax().clone()), + ast::Adt::Struct(it) => it.field_list().map(|list| list.syntax().clone()), + ast::Adt::Union(it) => it.record_field_list().map(|list| list.syntax().clone()), }; - let associated_types = node - .descendants() - .filter_map(PathType::cast) - .filter(is_associated_type) + let associated_types = field_list + .into_iter() + .flat_map(|it| it.descendants()) + .filter_map(ast::PathType::cast) + .filter_map(|p| { + let name = p.path()?.qualifier()?.as_single_name_ref()?.as_name(); + param_type_set.contains(&name).then_some(p) + }) .map(|x| mbe::syntax_node_to_token_tree(x.syntax()).0) - .collect::<Vec<_>>(); + .collect(); let name_token = name_to_token(&token_map, name)?; Ok(BasicAdtInfo { name: name_token, shape, param_types, associated_types }) } @@ -297,7 +305,7 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> { fn name_to_token(token_map: &TokenMap, name: Option<ast::Name>) -> Result<tt::Ident, ExpandError> { let name = name.ok_or_else(|| { debug!("parsed item has no name"); - ExpandError::Other("missing name".into()) + ExpandError::other("missing name") })?; let name_token_id = token_map.token_by_range(name.syntax().text_range()).unwrap_or_else(TokenId::unspecified); @@ -334,18 +342,18 @@ fn name_to_token(token_map: &TokenMap, name: Option<ast::Name>) -> Result<tt::Id /// } /// ``` /// -/// where B1, ..., BN are the bounds given by `bounds_paths`.'. Z is a phantom type, and +/// where B1, ..., BN are the bounds given by `bounds_paths`. Z is a phantom type, and /// therefore does not get bound by the derived trait. fn expand_simple_derive( tt: &tt::Subtree, trait_path: tt::Subtree, - trait_body: impl FnOnce(&BasicAdtInfo) -> tt::Subtree, + make_trait_body: impl FnOnce(&BasicAdtInfo) -> tt::Subtree, ) -> ExpandResult<tt::Subtree> { let info = match parse_adt(tt) { Ok(info) => info, Err(e) => return ExpandResult::new(tt::Subtree::empty(), e), }; - let trait_body = trait_body(&info); + let trait_body = make_trait_body(&info); let mut where_block = vec![]; let (params, args): (Vec<_>, Vec<_>) = info .param_types @@ -605,7 +613,7 @@ fn hash_expand( span: tt::TokenId::unspecified(), }; return quote! { - fn hash<H: #krate::hash::Hasher>(&self, state: &mut H) { + fn hash<H: #krate::hash::Hasher>(&self, ra_expand_state: &mut H) { match #star self {} } }; @@ -613,7 +621,7 @@ fn hash_expand( let arms = adt.shape.as_pattern(&adt.name).into_iter().zip(adt.shape.field_names()).map( |(pat, names)| { let expr = { - let it = names.iter().map(|x| quote! { #x . hash(state); }); + let it = names.iter().map(|x| quote! { #x . hash(ra_expand_state); }); quote! { { ##it } } @@ -625,8 +633,8 @@ fn hash_expand( }, ); quote! { - fn hash<H: #krate::hash::Hasher>(&self, state: &mut H) { - #krate::mem::discriminant(self).hash(state); + fn hash<H: #krate::hash::Hasher>(&self, ra_expand_state: &mut H) { + #krate::mem::discriminant(self).hash(ra_expand_state); match self { ##arms } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs index c7643bd0a18..a9f0c154b02 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs @@ -14,7 +14,8 @@ use syntax::{ }; use crate::{ - db::ExpandDatabase, name, quote, tt, ExpandError, ExpandResult, MacroCallId, MacroCallLoc, + db::ExpandDatabase, name, quote, tt, EagerCallInfo, ExpandError, ExpandResult, MacroCallId, + MacroCallLoc, }; macro_rules! register_builtin { @@ -49,7 +50,7 @@ macro_rules! register_builtin { db: &dyn ExpandDatabase, arg_id: MacroCallId, tt: &tt::Subtree, - ) -> ExpandResult<ExpandedEager> { + ) -> ExpandResult<tt::Subtree> { let expander = match *self { $( EagerExpander::$e_kind => $e_expand, )* }; @@ -67,16 +68,9 @@ macro_rules! register_builtin { }; } -#[derive(Debug)] -pub struct ExpandedEager { - pub(crate) subtree: tt::Subtree, - /// The included file ID of the include macro. - pub(crate) included_file: Option<(FileId, TokenMap)>, -} - -impl ExpandedEager { - fn new(subtree: tt::Subtree) -> Self { - ExpandedEager { subtree, included_file: None } +impl EagerExpander { + pub fn is_include(&self) -> bool { + matches!(self, EagerExpander::Include) } } @@ -237,18 +231,16 @@ fn format_args_expand( db: &dyn ExpandDatabase, id: MacroCallId, tt: &tt::Subtree, -) -> ExpandResult<ExpandedEager> { +) -> ExpandResult<tt::Subtree> { format_args_expand_general(db, id, tt, "") - .map(|x| ExpandedEager { subtree: x, included_file: None }) } fn format_args_nl_expand( db: &dyn ExpandDatabase, id: MacroCallId, tt: &tt::Subtree, -) -> ExpandResult<ExpandedEager> { +) -> ExpandResult<tt::Subtree> { format_args_expand_general(db, id, tt, "\\n") - .map(|x| ExpandedEager { subtree: x, included_file: None }) } fn format_args_expand_general( @@ -262,9 +254,6 @@ fn format_args_expand_general( let expand_error = ExpandResult::new(tt::Subtree::empty(), mbe::ExpandError::NoMatchingRule.into()); - if args.is_empty() { - return expand_error; - } let mut key_args = FxHashMap::default(); let mut args = args.into_iter().filter_map(|mut arg| { // Remove `key =`. @@ -281,7 +270,9 @@ fn format_args_expand_general( Some(arg) }).collect::<Vec<_>>().into_iter(); // ^^^^^^^ we need this collect, to enforce the side effect of the filter_map closure (building the `key_args`) - let format_subtree = args.next().unwrap(); + let Some(format_subtree) = args.next() else { + return expand_error; + }; let format_string = (|| { let token_tree = format_subtree.token_trees.get(0)?; match token_tree { @@ -510,23 +501,23 @@ fn compile_error_expand( _db: &dyn ExpandDatabase, _id: MacroCallId, tt: &tt::Subtree, -) -> ExpandResult<ExpandedEager> { +) -> ExpandResult<tt::Subtree> { let err = match &*tt.token_trees { [tt::TokenTree::Leaf(tt::Leaf::Literal(it))] => match unquote_str(it) { - Some(unquoted) => ExpandError::Other(unquoted.into()), - None => ExpandError::Other("`compile_error!` argument must be a string".into()), + Some(unquoted) => ExpandError::other(unquoted), + None => ExpandError::other("`compile_error!` argument must be a string"), }, - _ => ExpandError::Other("`compile_error!` argument must be a string".into()), + _ => ExpandError::other("`compile_error!` argument must be a string"), }; - ExpandResult { value: ExpandedEager::new(quote! {}), err: Some(err) } + ExpandResult { value: quote! {}, err: Some(err) } } fn concat_expand( _db: &dyn ExpandDatabase, _arg_id: MacroCallId, tt: &tt::Subtree, -) -> ExpandResult<ExpandedEager> { +) -> ExpandResult<tt::Subtree> { let mut err = None; let mut text = String::new(); for (i, mut t) in tt.token_trees.iter().enumerate() { @@ -565,14 +556,14 @@ fn concat_expand( } } } - ExpandResult { value: ExpandedEager::new(quote!(#text)), err } + ExpandResult { value: quote!(#text), err } } fn concat_bytes_expand( _db: &dyn ExpandDatabase, _arg_id: MacroCallId, tt: &tt::Subtree, -) -> ExpandResult<ExpandedEager> { +) -> ExpandResult<tt::Subtree> { let mut bytes = Vec::new(); let mut err = None; for (i, t) in tt.token_trees.iter().enumerate() { @@ -605,7 +596,7 @@ fn concat_bytes_expand( } } let ident = tt::Ident { text: bytes.join(", ").into(), span: tt::TokenId::unspecified() }; - ExpandResult { value: ExpandedEager::new(quote!([#ident])), err } + ExpandResult { value: quote!([#ident]), err } } fn concat_bytes_expand_subtree( @@ -638,7 +629,7 @@ fn concat_idents_expand( _db: &dyn ExpandDatabase, _arg_id: MacroCallId, tt: &tt::Subtree, -) -> ExpandResult<ExpandedEager> { +) -> ExpandResult<tt::Subtree> { let mut err = None; let mut ident = String::new(); for (i, t) in tt.token_trees.iter().enumerate() { @@ -653,7 +644,7 @@ fn concat_idents_expand( } } let ident = tt::Ident { text: ident.into(), span: tt::TokenId::unspecified() }; - ExpandResult { value: ExpandedEager::new(quote!(#ident)), err } + ExpandResult { value: quote!(#ident), err } } fn relative_file( @@ -666,10 +657,10 @@ fn relative_file( let path = AnchoredPath { anchor: call_site, path: path_str }; let res = db .resolve_path(path) - .ok_or_else(|| ExpandError::Other(format!("failed to load file `{path_str}`").into()))?; + .ok_or_else(|| ExpandError::other(format!("failed to load file `{path_str}`")))?; // Prevent include itself if res == call_site && !allow_recursion { - Err(ExpandError::Other(format!("recursive inclusion of `{path_str}`").into())) + Err(ExpandError::other(format!("recursive inclusion of `{path_str}`"))) } else { Ok(res) } @@ -688,38 +679,37 @@ fn parse_string(tt: &tt::Subtree) -> Result<String, ExpandError> { fn include_expand( db: &dyn ExpandDatabase, arg_id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult<ExpandedEager> { - let res = (|| { - let path = parse_string(tt)?; - let file_id = relative_file(db, arg_id, &path, false)?; - - let (subtree, map) = - parse_to_token_tree(&db.file_text(file_id)).ok_or(mbe::ExpandError::ConversionError)?; - Ok((subtree, map, file_id)) - })(); - - match res { - Ok((subtree, map, file_id)) => { - ExpandResult::ok(ExpandedEager { subtree, included_file: Some((file_id, map)) }) - } - Err(e) => ExpandResult::new( - ExpandedEager { subtree: tt::Subtree::empty(), included_file: None }, - e, - ), + _tt: &tt::Subtree, +) -> ExpandResult<tt::Subtree> { + match db.include_expand(arg_id) { + Ok((res, _)) => ExpandResult::ok(res.0.clone()), + Err(e) => ExpandResult::new(tt::Subtree::empty(), e), } } +pub(crate) fn include_arg_to_tt( + db: &dyn ExpandDatabase, + arg_id: MacroCallId, +) -> Result<(triomphe::Arc<(::tt::Subtree<::tt::TokenId>, TokenMap)>, FileId), ExpandError> { + let loc = db.lookup_intern_macro_call(arg_id); + let Some(EagerCallInfo {arg, arg_id: Some(arg_id), .. }) = loc.eager.as_deref() else { + panic!("include_arg_to_tt called on non include macro call: {:?}", &loc.eager); + }; + let path = parse_string(&arg.0)?; + let file_id = relative_file(db, *arg_id, &path, false)?; + + let (subtree, map) = + parse_to_token_tree(&db.file_text(file_id)).ok_or(mbe::ExpandError::ConversionError)?; + Ok((triomphe::Arc::new((subtree, map)), file_id)) +} + fn include_bytes_expand( _db: &dyn ExpandDatabase, _arg_id: MacroCallId, tt: &tt::Subtree, -) -> ExpandResult<ExpandedEager> { +) -> ExpandResult<tt::Subtree> { if let Err(e) = parse_string(tt) { - return ExpandResult::new( - ExpandedEager { subtree: tt::Subtree::empty(), included_file: None }, - e, - ); + return ExpandResult::new(tt::Subtree::empty(), e); } // FIXME: actually read the file here if the user asked for macro expansion @@ -730,22 +720,17 @@ fn include_bytes_expand( span: tt::TokenId::unspecified(), }))], }; - ExpandResult::ok(ExpandedEager::new(res)) + ExpandResult::ok(res) } fn include_str_expand( db: &dyn ExpandDatabase, arg_id: MacroCallId, tt: &tt::Subtree, -) -> ExpandResult<ExpandedEager> { +) -> ExpandResult<tt::Subtree> { let path = match parse_string(tt) { Ok(it) => it, - Err(e) => { - return ExpandResult::new( - ExpandedEager { subtree: tt::Subtree::empty(), included_file: None }, - e, - ) - } + Err(e) => return ExpandResult::new(tt::Subtree::empty(), e), }; // FIXME: we're not able to read excluded files (which is most of them because @@ -755,14 +740,14 @@ fn include_str_expand( let file_id = match relative_file(db, arg_id, &path, true) { Ok(file_id) => file_id, Err(_) => { - return ExpandResult::ok(ExpandedEager::new(quote!(""))); + return ExpandResult::ok(quote!("")); } }; let text = db.file_text(file_id); let text = &*text; - ExpandResult::ok(ExpandedEager::new(quote!(#text))) + ExpandResult::ok(quote!(#text)) } fn get_env_inner(db: &dyn ExpandDatabase, arg_id: MacroCallId, key: &str) -> Option<String> { @@ -774,15 +759,10 @@ fn env_expand( db: &dyn ExpandDatabase, arg_id: MacroCallId, tt: &tt::Subtree, -) -> ExpandResult<ExpandedEager> { +) -> ExpandResult<tt::Subtree> { let key = match parse_string(tt) { Ok(it) => it, - Err(e) => { - return ExpandResult::new( - ExpandedEager { subtree: tt::Subtree::empty(), included_file: None }, - e, - ) - } + Err(e) => return ExpandResult::new(tt::Subtree::empty(), e), }; let mut err = None; @@ -790,35 +770,28 @@ fn env_expand( // The only variable rust-analyzer ever sets is `OUT_DIR`, so only diagnose that to avoid // unnecessary diagnostics for eg. `CARGO_PKG_NAME`. if key == "OUT_DIR" { - err = Some(ExpandError::Other( - r#"`OUT_DIR` not set, enable "build scripts" to fix"#.into(), - )); + err = Some(ExpandError::other(r#"`OUT_DIR` not set, enable "build scripts" to fix"#)); } // If the variable is unset, still return a dummy string to help type inference along. // We cannot use an empty string here, because for // `include!(concat!(env!("OUT_DIR"), "/foo.rs"))` will become // `include!("foo.rs"), which might go to infinite loop - "__RA_UNIMPLEMENTED__".to_string() + "UNRESOLVED_ENV_VAR".to_string() }); let expanded = quote! { #s }; - ExpandResult { value: ExpandedEager::new(expanded), err } + ExpandResult { value: expanded, err } } fn option_env_expand( db: &dyn ExpandDatabase, arg_id: MacroCallId, tt: &tt::Subtree, -) -> ExpandResult<ExpandedEager> { +) -> ExpandResult<tt::Subtree> { let key = match parse_string(tt) { Ok(it) => it, - Err(e) => { - return ExpandResult::new( - ExpandedEager { subtree: tt::Subtree::empty(), included_file: None }, - e, - ) - } + Err(e) => return ExpandResult::new(tt::Subtree::empty(), e), }; // FIXME: Use `DOLLAR_CRATE` when that works in eager macros. let expanded = match get_env_inner(db, arg_id, &key) { @@ -826,5 +799,5 @@ fn option_env_expand( Some(s) => quote! { ::core::option::Option::Some(#s) }, }; - ExpandResult::ok(ExpandedEager::new(expanded)) + ExpandResult::ok(expanded) } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs index 965dfa824d8..78b2db7306b 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -14,9 +14,9 @@ use triomphe::Arc; use crate::{ ast_id_map::AstIdMap, builtin_attr_macro::pseudo_derive_attr_expansion, builtin_fn_macro::EagerExpander, fixup, hygiene::HygieneFrame, tt, BuiltinAttrExpander, - BuiltinDeriveExpander, BuiltinFnLikeExpander, ExpandError, ExpandResult, ExpandTo, HirFileId, - HirFileIdRepr, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, - ProcMacroExpander, + BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo, ExpandError, ExpandResult, + ExpandTo, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, + MacroDefKind, MacroFile, ProcMacroExpander, }; /// Total limit on the number of tokens produced by any macro invocation. @@ -53,9 +53,7 @@ impl TokenExpander { match self { TokenExpander::DeclarativeMacro { mac, .. } => mac.expand(tt).map_err(Into::into), TokenExpander::Builtin(it) => it.expand(db, id, tt).map_err(Into::into), - TokenExpander::BuiltinEager(it) => { - it.expand(db, id, tt).map_err(Into::into).map(|res| res.subtree) - } + TokenExpander::BuiltinEager(it) => it.expand(db, id, tt).map_err(Into::into), TokenExpander::BuiltinAttr(it) => it.expand(db, id, tt), TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt), TokenExpander::ProcMacro(_) => { @@ -132,6 +130,14 @@ pub trait ExpandDatabase: SourceDatabase { /// Expand macro call to a token tree. // This query is LRU cached fn macro_expand(&self, macro_call: MacroCallId) -> ExpandResult<Arc<tt::Subtree>>; + #[salsa::invoke(crate::builtin_fn_macro::include_arg_to_tt)] + fn include_expand( + &self, + arg_id: MacroCallId, + ) -> Result< + (triomphe::Arc<(::tt::Subtree<::tt::TokenId>, mbe::TokenMap)>, base_db::FileId), + ExpandError, + >; /// Special case of the previous query for procedural macros. We can't LRU /// proc macros, since they are not deterministic in general, and /// non-determinism breaks salsa in a very, very, very bad way. @@ -281,31 +287,6 @@ fn parse_macro_expansion( let _p = profile::span("parse_macro_expansion"); let mbe::ValueResult { value: tt, err } = db.macro_expand(macro_file.macro_call_id); - if let Some(err) = &err { - if tracing::enabled!(tracing::Level::DEBUG) { - // Note: - // The final goal we would like to make all parse_macro success, - // such that the following log will not call anyway. - let loc = db.lookup_intern_macro_call(macro_file.macro_call_id); - let node = loc.to_node(db); - - // collect parent information for warning log - let parents = std::iter::successors(loc.kind.file_id().call_node(db), |it| { - it.file_id.call_node(db) - }) - .map(|n| format!("{:#}", n.value)) - .collect::<Vec<_>>() - .join("\n"); - - tracing::debug!( - "fail on macro_parse: (reason: {:?} macro_call: {:#}) parents: {}", - err, - node.value, - parents - ); - } - } - let expand_to = macro_expand_to(db, macro_file.macro_call_id); tracing::debug!("expanded = {}", tt.as_debug_string()); @@ -320,9 +301,14 @@ fn macro_arg( db: &dyn ExpandDatabase, id: MacroCallId, ) -> Option<Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupUndoInfo)>> { - let arg = db.macro_arg_text(id)?; let loc = db.lookup_intern_macro_call(id); + if let Some(EagerCallInfo { arg, arg_id: Some(_), error: _ }) = loc.eager.as_deref() { + return Some(Arc::new((arg.0.clone(), arg.1.clone(), Default::default()))); + } + + let arg = db.macro_arg_text(id)?; + let node = SyntaxNode::new_root(arg); let censor = censor_for_macro_input(&loc, &node); let mut fixups = fixup::fixup_syntax(&node); @@ -398,7 +384,17 @@ fn macro_arg_text(db: &dyn ExpandDatabase, id: MacroCallId) -> Option<GreenNode> return None; } } - Some(arg.green().into()) + if let Some(EagerCallInfo { arg, .. }) = loc.eager.as_deref() { + Some( + mbe::token_tree_to_syntax_node(&arg.0, mbe::TopEntryPoint::Expr) + .0 + .syntax_node() + .green() + .into(), + ) + } else { + Some(arg.green().into()) + } } fn macro_def( @@ -445,23 +441,21 @@ fn macro_def( fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt::Subtree>> { let _p = profile::span("macro_expand"); let loc = db.lookup_intern_macro_call(id); - if let Some(eager) = &loc.eager { - return ExpandResult { value: eager.arg_or_expansion.clone(), err: eager.error.clone() }; + if let Some(EagerCallInfo { arg, arg_id: None, error }) = loc.eager.as_deref() { + // This is an input expansion for an eager macro. These are already pre-expanded + return ExpandResult { value: Arc::new(arg.0.clone()), err: error.clone() }; } - let expander = match db.macro_def(loc.def) { Ok(it) => it, - // FIXME: This is weird -- we effectively report macro *definition* - // errors lazily, when we try to expand the macro. Instead, they should - // be reported at the definition site when we construct a def map. - // (Note we do report them also at the definition site in the late diagnostic pass) + // FIXME: We should make sure to enforce a variant that invalid macro + // definitions do not get expanders that could reach this call path! Err(err) => { return ExpandResult { value: Arc::new(tt::Subtree { delimiter: tt::Delimiter::UNSPECIFIED, token_trees: vec![], }), - err: Some(ExpandError::Other(format!("invalid macro definition: {err}").into())), + err: Some(ExpandError::other(format!("invalid macro definition: {err}"))), } } }; @@ -473,13 +467,21 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt token_trees: Vec::new(), }, ), - err: Some(ExpandError::Other( + // FIXME: We should make sure to enforce a variant that invalid macro + // calls do not reach this call path! + err: Some(ExpandError::other( "invalid token tree" - .into(), )), }; }; - let ExpandResult { value: mut tt, err } = expander.expand(db, id, ¯o_arg.0); + let (arg_tt, arg_tm, undo_info) = &*macro_arg; + let ExpandResult { value: mut tt, mut err } = expander.expand(db, id, arg_tt); + + if let Some(EagerCallInfo { error, .. }) = loc.eager.as_deref() { + // FIXME: We should report both errors! + err = error.clone().or(err); + } + // Set a hard limit for the expanded tt let count = tt.count(); if TOKEN_LIMIT.check(count).is_err() { @@ -488,18 +490,15 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt delimiter: tt::Delimiter::UNSPECIFIED, token_trees: vec![], }), - err: Some(ExpandError::Other( - format!( - "macro invocation exceeds token limit: produced {} tokens, limit is {}", - count, - TOKEN_LIMIT.inner(), - ) - .into(), - )), + err: Some(ExpandError::other(format!( + "macro invocation exceeds token limit: produced {} tokens, limit is {}", + count, + TOKEN_LIMIT.inner(), + ))), }; } - fixup::reverse_fixups(&mut tt, ¯o_arg.1, ¯o_arg.2); + fixup::reverse_fixups(&mut tt, arg_tm, undo_info); ExpandResult { value: Arc::new(tt), err } } @@ -520,9 +519,8 @@ fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<t delimiter: tt::Delimiter::UNSPECIFIED, token_trees: Vec::new(), }, - err: Some(ExpandError::Other( + err: Some(ExpandError::other( "invalid token tree" - .into(), )), }; }; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs index 59a92ff0ab6..7ee3fd375f6 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs @@ -31,22 +31,24 @@ use crate::{ MacroCallLoc, MacroDefId, MacroDefKind, UnresolvedMacro, }; -pub fn expand_eager_macro( +pub fn expand_eager_macro_input( db: &dyn ExpandDatabase, krate: CrateId, macro_call: InFile<ast::MacroCall>, def: MacroDefId, resolver: &dyn Fn(ModPath) -> Option<MacroDefId>, ) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro> { - let MacroDefKind::BuiltInEager(eager, _) = def.kind else { - panic!("called `expand_eager_macro` on non-eager macro def {def:?}") + assert!(matches!(def.kind, MacroDefKind::BuiltInEager(..))); + let token_tree = macro_call.value.token_tree(); + + let Some(token_tree) = token_tree else { + return Ok(ExpandResult { value: None, err: + Some(ExpandError::other( + "invalid token tree" + )), + }); }; - let hygiene = Hygiene::new(db, macro_call.file_id); - let parsed_args = macro_call - .value - .token_tree() - .map(|tt| mbe::syntax_node_to_token_tree(tt.syntax()).0) - .unwrap_or_else(tt::Subtree::empty); + let (parsed_args, arg_token_map) = mbe::syntax_node_to_token_tree(token_tree.syntax()); let ast_map = db.ast_id_map(macro_call.file_id); let call_id = InFile::new(macro_call.file_id, ast_map.ast_id(¯o_call.value)); @@ -60,41 +62,40 @@ pub fn expand_eager_macro( def, krate, eager: Some(Box::new(EagerCallInfo { - arg_or_expansion: Arc::new(parsed_args.clone()), - included_file: None, + arg: Arc::new((parsed_args, arg_token_map)), + arg_id: None, error: None, })), kind: MacroCallKind::FnLike { ast_id: call_id, expand_to: ExpandTo::Expr }, }); - - let parsed_args = mbe::token_tree_to_syntax_node(&parsed_args, mbe::TopEntryPoint::Expr).0; - let ExpandResult { value, mut err } = eager_macro_recur( + let arg_as_expr = match db.macro_arg_text(arg_id) { + Some(it) => it, + None => { + return Ok(ExpandResult { + value: None, + err: Some(ExpandError::other("invalid token tree")), + }) + } + }; + let ExpandResult { value: expanded_eager_input, err } = eager_macro_recur( db, - &hygiene, - InFile::new(arg_id.as_file(), parsed_args.syntax_node()), + &Hygiene::new(db, macro_call.file_id), + InFile::new(arg_id.as_file(), SyntaxNode::new_root(arg_as_expr)), krate, resolver, )?; - let Some(value ) = value else { + let Some(expanded_eager_input) = expanded_eager_input else { return Ok(ExpandResult { value: None, err }) }; - let subtree = { - let mut subtree = mbe::syntax_node_to_token_tree(&value).0; - subtree.delimiter = crate::tt::Delimiter::unspecified(); - subtree - }; - - let res = eager.expand(db, arg_id, &subtree); - if err.is_none() { - err = res.err; - } + let (mut subtree, token_map) = mbe::syntax_node_to_token_tree(&expanded_eager_input); + subtree.delimiter = crate::tt::Delimiter::unspecified(); let loc = MacroCallLoc { def, krate, eager: Some(Box::new(EagerCallInfo { - arg_or_expansion: Arc::new(res.value.subtree), - included_file: res.value.included_file, + arg: Arc::new((subtree, token_map)), + arg_id: Some(arg_id), error: err.clone(), })), kind: MacroCallKind::FnLike { ast_id: call_id, expand_to }, @@ -118,8 +119,9 @@ fn lazy_expand( MacroCallKind::FnLike { ast_id: macro_call.with_value(ast_id), expand_to }, ); - let file_id = id.as_file(); - db.parse_or_expand_with_err(file_id).map(|parse| InFile::new(file_id, parse)) + let macro_file = id.as_macro_file(); + + db.parse_macro_expansion(macro_file).map(|parse| InFile::new(macro_file.into(), parse.0)) } fn eager_macro_recur( @@ -142,13 +144,13 @@ fn eager_macro_recur( let def = match child.path().and_then(|path| ModPath::from_src(db, path, hygiene)) { Some(path) => macro_resolver(path.clone()).ok_or(UnresolvedMacro { path })?, None => { - error = Some(ExpandError::Other("malformed macro invocation".into())); + error = Some(ExpandError::other("malformed macro invocation")); continue; } }; let ExpandResult { value, err } = match def.kind { MacroDefKind::BuiltInEager(..) => { - let id = match expand_eager_macro( + let ExpandResult { value, err } = match expand_eager_macro_input( db, krate, curr.with_value(child.clone()), @@ -158,9 +160,17 @@ fn eager_macro_recur( Ok(it) => it, Err(err) => return Err(err), }; - id.map(|call| { - call.map(|call| db.parse_or_expand(call.as_file()).clone_for_update()) - }) + match value { + Some(call) => { + let ExpandResult { value, err: err2 } = + db.parse_macro_expansion(call.as_macro_file()); + ExpandResult { + value: Some(value.0.syntax_node().clone_for_update()), + err: err.or(err2), + } + } + None => ExpandResult { value: None, err }, + } } MacroDefKind::Declarative(_) | MacroDefKind::BuiltIn(..) @@ -180,7 +190,7 @@ fn eager_macro_recur( krate, macro_resolver, )?; - let err = if err.is_none() { error } else { err }; + let err = err.or(error); ExpandResult { value, err } } }; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index c8373778d32..e0c199328ef 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -58,7 +58,13 @@ pub enum ExpandError { UnresolvedProcMacro(CrateId), Mbe(mbe::ExpandError), RecursionOverflowPoisoned, - Other(Box<str>), + Other(Box<Box<str>>), +} + +impl ExpandError { + pub fn other(msg: impl Into<Box<str>>) -> Self { + ExpandError::Other(Box::new(msg.into())) + } } impl From<mbe::ExpandError> for ExpandError { @@ -97,9 +103,15 @@ impl fmt::Display for ExpandError { /// The two variants are encoded in a single u32 which are differentiated by the MSB. /// If the MSB is 0, the value represents a `FileId`, otherwise the remaining 31 bits represent a /// `MacroCallId`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct HirFileId(u32); +impl fmt::Debug for HirFileId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.repr().fmt(f) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct MacroFile { pub macro_call_id: MacroCallId, @@ -115,6 +127,7 @@ impl_intern_key!(MacroCallId); pub struct MacroCallLoc { pub def: MacroDefId, pub(crate) krate: CrateId, + /// Some if `def` is a builtin eager macro. eager: Option<Box<EagerCallInfo>>, pub kind: MacroCallKind, } @@ -140,8 +153,10 @@ pub enum MacroDefKind { #[derive(Debug, Clone, PartialEq, Eq, Hash)] struct EagerCallInfo { /// NOTE: This can be *either* the expansion result, *or* the argument to the eager macro! - arg_or_expansion: Arc<tt::Subtree>, - included_file: Option<(FileId, TokenMap)>, + arg: Arc<(tt::Subtree, TokenMap)>, + /// call id of the eager macro's input file. If this is none, macro call containing this call info + /// is an eager macro's input, otherwise it is its output. + arg_id: Option<MacroCallId>, error: Option<ExpandError>, } @@ -206,10 +221,15 @@ impl HirFileId { HirFileIdRepr::FileId(id) => break id, HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => { let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_call_id); - file_id = match loc.eager.as_deref() { - Some(&EagerCallInfo { included_file: Some((file, _)), .. }) => file.into(), + let is_include_expansion = loc.def.is_include() + && matches!( + loc.eager.as_deref(), + Some(EagerCallInfo { arg_id: Some(_), .. }) + ); + file_id = match is_include_expansion.then(|| db.include_expand(macro_call_id)) { + Some(Ok((_, file))) => file.into(), _ => loc.kind.file_id(), - }; + } } } } @@ -325,7 +345,17 @@ impl HirFileId { match self.macro_file() { Some(macro_file) => { let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); - matches!(loc.eager.as_deref(), Some(EagerCallInfo { included_file: Some(..), .. })) + loc.def.is_include() + } + _ => false, + } + } + + pub fn is_eager(&self, db: &dyn db::ExpandDatabase) -> bool { + match self.macro_file() { + Some(macro_file) => { + let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); + matches!(loc.eager.as_deref(), Some(EagerCallInfo { .. })) } _ => false, } @@ -423,6 +453,10 @@ impl MacroDefId { pub fn is_attribute_derive(&self) -> bool { matches!(self.kind, MacroDefKind::BuiltInAttr(expander, ..) if expander.is_derive()) } + + pub fn is_include(&self) -> bool { + matches!(self.kind, MacroDefKind::BuiltInEager(expander, ..) if expander.is_include()) + } } impl MacroCallLoc { @@ -569,6 +603,10 @@ impl MacroCallId { pub fn as_file(self) -> HirFileId { MacroFile { macro_call_id: self }.into() } + + pub fn as_macro_file(self) -> MacroFile { + MacroFile { macro_call_id: self } + } } /// ExpansionInfo mainly describes how to map text range between src and expanded macro @@ -662,7 +700,7 @@ impl ExpansionInfo { let token_id = match token_id_in_attr_input { Some(token_id) => token_id, - // the token is not inside an attribute's input so do the lookup in the macro_arg as usual + // the token is not inside `an attribute's input so do the lookup in the macro_arg as usual None => { let relative_range = token.value.text_range().checked_sub(self.arg.value.text_range().start())?; @@ -694,14 +732,18 @@ impl ExpansionInfo { let call_id = self.expanded.file_id.macro_file()?.macro_call_id; let loc = db.lookup_intern_macro_call(call_id); - if let Some((file, map)) = loc.eager.and_then(|e| e.included_file) { - // Special case: map tokens from `include!` expansions to the included file - let range = map.first_range_by_token(token_id, token.value.kind())?; - let source = db.parse(file); + // Special case: map tokens from `include!` expansions to the included file + if loc.def.is_include() + && matches!(loc.eager.as_deref(), Some(EagerCallInfo { arg_id: Some(_), .. })) + { + if let Ok((tt_and_map, file_id)) = db.include_expand(call_id) { + let range = tt_and_map.1.first_range_by_token(token_id, token.value.kind())?; + let source = db.parse(file_id); - let token = source.syntax_node().covering_element(range).into_token()?; + let token = source.syntax_node().covering_element(range).into_token()?; - return Some((InFile::new(file.into(), token), Origin::Call)); + return Some((InFile::new(file_id.into(), token), Origin::Call)); + } } // Attributes are a bit special for us, they have two inputs, the input tokentree and the annotated item. diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs index c9539210abf..41675c630dc 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs @@ -46,7 +46,7 @@ impl ProcMacroExpander { never!("Non-dummy expander even though there are no proc macros"); return ExpandResult::new( tt::Subtree::empty(), - ExpandError::Other("Internal error".into()), + ExpandError::other("Internal error"), ); } }; @@ -60,7 +60,7 @@ impl ProcMacroExpander { ); return ExpandResult::new( tt::Subtree::empty(), - ExpandError::Other("Internal error".into()), + ExpandError::other("Internal error"), ); } }; @@ -75,14 +75,11 @@ impl ProcMacroExpander { ProcMacroExpansionError::System(text) if proc_macro.kind == ProcMacroKind::Attr => { - ExpandResult { - value: tt.clone(), - err: Some(ExpandError::Other(text.into())), - } + ExpandResult { value: tt.clone(), err: Some(ExpandError::other(text)) } } ProcMacroExpansionError::System(text) | ProcMacroExpansionError::Panic(text) => { - ExpandResult::new(tt::Subtree::empty(), ExpandError::Other(text.into())) + ExpandResult::new(tt::Subtree::empty(), ExpandError::other(text)) } }, } diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml index 6ca0dbb8503..c8bea34507c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml @@ -22,10 +22,10 @@ either = "1.7.0" tracing = "0.1.35" rustc-hash = "1.1.0" scoped-tls = "1.0.0" -chalk-solve = { version = "0.89.0", default-features = false } -chalk-ir = "0.89.0" -chalk-recursive = { version = "0.89.0", default-features = false } -chalk-derive = "0.89.0" +chalk-solve = { version = "0.91.0", default-features = false } +chalk-ir = "0.91.0" +chalk-recursive = { version = "0.91.0", default-features = false } +chalk-derive = "0.91.0" la-arena = { version = "0.3.0", path = "../../lib/la-arena" } once_cell = "1.17.0" triomphe.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs index f5b3f176b12..3860bccec8b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs @@ -22,17 +22,37 @@ pub(crate) enum AutoderefKind { Overloaded, } +/// Returns types that `ty` transitively dereferences to. This function is only meant to be used +/// outside `hir-ty`. +/// +/// It is guaranteed that: +/// - the yielded types don't contain inference variables (but may contain `TyKind::Error`). +/// - a type won't be yielded more than once; in other words, the returned iterator will stop if it +/// detects a cycle in the deref chain. pub fn autoderef( db: &dyn HirDatabase, env: Arc<TraitEnvironment>, ty: Canonical<Ty>, -) -> impl Iterator<Item = Canonical<Ty>> + '_ { +) -> impl Iterator<Item = Ty> { let mut table = InferenceTable::new(db, env); let ty = table.instantiate_canonical(ty); let mut autoderef = Autoderef::new(&mut table, ty); let mut v = Vec::new(); while let Some((ty, _steps)) = autoderef.next() { - v.push(autoderef.table.canonicalize(ty).value); + // `ty` may contain unresolved inference variables. Since there's no chance they would be + // resolved, just replace with fallback type. + let resolved = autoderef.table.resolve_completely(ty); + + // If the deref chain contains a cycle (e.g. `A` derefs to `B` and `B` derefs to `A`), we + // would revisit some already visited types. Stop here to avoid duplication. + // + // XXX: The recursion limit for `Autoderef` is currently 10, so `Vec::contains()` shouldn't + // be too expensive. Replace this duplicate check with `FxHashSet` if it proves to be more + // performant. + if v.contains(&resolved) { + break; + } + v.push(resolved); } v.into_iter() } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index ac962c9e3e1..5dd8e2719a2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -497,7 +497,7 @@ pub(crate) fn associated_ty_data_query( let generic_params = generics(db.upcast(), type_alias.into()); // let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST); let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast()); - let ctx = crate::TyLoweringContext::new(db, &resolver) + let ctx = crate::TyLoweringContext::new(db, &resolver, type_alias.into()) .with_type_param_mode(crate::lower::ParamLoweringMode::Variable); let trait_subst = TyBuilder::subst_for_def(db, trait_, None) @@ -592,6 +592,7 @@ fn well_known_trait_from_lang_item(item: LangItem) -> Option<WellKnownTrait> { LangItem::Unpin => WellKnownTrait::Unpin, LangItem::Unsize => WellKnownTrait::Unsize, LangItem::Tuple => WellKnownTrait::Tuple, + LangItem::PointeeTrait => WellKnownTrait::Pointee, _ => return None, }) } @@ -612,6 +613,7 @@ fn lang_item_from_well_known_trait(trait_: WellKnownTrait) -> LangItem { WellKnownTrait::Tuple => LangItem::Tuple, WellKnownTrait::Unpin => LangItem::Unpin, WellKnownTrait::Unsize => LangItem::Unsize, + WellKnownTrait::Pointee => LangItem::PointeeTrait, } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs index 40b63b17b5a..262341c6e9e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -6,8 +6,8 @@ use hir_def::{ hir::Expr, path::Path, resolver::{Resolver, ValueNs}, - type_ref::ConstRef, - EnumVariantId, GeneralConstId, StaticId, + type_ref::LiteralConstRef, + ConstBlockLoc, EnumVariantId, GeneralConstId, StaticId, }; use la_arena::{Idx, RawIdx}; use stdx::never; @@ -129,23 +129,28 @@ pub fn intern_const_scalar(value: ConstScalar, ty: Ty) -> Const { } /// Interns a constant scalar with the given type -pub fn intern_const_ref(db: &dyn HirDatabase, value: &ConstRef, ty: Ty, krate: CrateId) -> Const { +pub fn intern_const_ref( + db: &dyn HirDatabase, + value: &LiteralConstRef, + ty: Ty, + krate: CrateId, +) -> Const { let layout = db.layout_of_ty(ty.clone(), krate); let bytes = match value { - ConstRef::Int(i) => { + LiteralConstRef::Int(i) => { // FIXME: We should handle failure of layout better. let size = layout.map(|x| x.size.bytes_usize()).unwrap_or(16); ConstScalar::Bytes(i.to_le_bytes()[0..size].to_vec(), MemoryMap::default()) } - ConstRef::UInt(i) => { + LiteralConstRef::UInt(i) => { let size = layout.map(|x| x.size.bytes_usize()).unwrap_or(16); ConstScalar::Bytes(i.to_le_bytes()[0..size].to_vec(), MemoryMap::default()) } - ConstRef::Bool(b) => ConstScalar::Bytes(vec![*b as u8], MemoryMap::default()), - ConstRef::Char(c) => { + LiteralConstRef::Bool(b) => ConstScalar::Bytes(vec![*b as u8], MemoryMap::default()), + LiteralConstRef::Char(c) => { ConstScalar::Bytes((*c as u32).to_le_bytes().to_vec(), MemoryMap::default()) } - ConstRef::Unknown => ConstScalar::Unknown, + LiteralConstRef::Unknown => ConstScalar::Unknown, }; intern_const_scalar(bytes, ty) } @@ -154,7 +159,7 @@ pub fn intern_const_ref(db: &dyn HirDatabase, value: &ConstRef, ty: Ty, krate: C pub fn usize_const(db: &dyn HirDatabase, value: Option<u128>, krate: CrateId) -> Const { intern_const_ref( db, - &value.map_or(ConstRef::Unknown, ConstRef::UInt), + &value.map_or(LiteralConstRef::Unknown, LiteralConstRef::UInt), TyBuilder::usize(), krate, ) @@ -210,17 +215,18 @@ pub(crate) fn const_eval_query( GeneralConstId::ConstId(c) => { db.monomorphized_mir_body(c.into(), subst, db.trait_environment(c.into()))? } - GeneralConstId::AnonymousConstId(c) => { - let (def, root) = db.lookup_intern_anonymous_const(c); - let body = db.body(def); - let infer = db.infer(def); + GeneralConstId::ConstBlockId(c) => { + let ConstBlockLoc { parent, root } = db.lookup_intern_anonymous_const(c); + let body = db.body(parent); + let infer = db.infer(parent); Arc::new(monomorphize_mir_body_bad( db, - lower_to_mir(db, def, &body, &infer, root)?, + lower_to_mir(db, parent, &body, &infer, root)?, subst, - db.trait_environment_for_body(def), + db.trait_environment_for_body(parent), )?) } + GeneralConstId::InTypeConstId(c) => db.mir_body(c.into())?, }; let c = interpret_mir(db, &body, false).0?; Ok(c) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs index 06fff08b7d3..0db1fefbfef 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs @@ -2052,6 +2052,17 @@ fn extern_weak_statics() { } #[test] +fn from_ne_bytes() { + check_number( + r#" +//- minicore: int_impl +const GOAL: u32 = u32::from_ne_bytes([44, 1, 0, 0]); + "#, + 300, + ); +} + +#[test] fn enums() { check_number( r#" diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index ca8a394e360..9dd810f844d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -278,6 +278,7 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> DefWithBodyId::VariantId(it) => { db.enum_data(it.parent).variants[it.local_id].name.display(db.upcast()).to_string() } + DefWithBodyId::InTypeConstId(it) => format!("in type const {it:?}"), }); db.infer_query(def) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs index 7c38e6583a7..9f9a56ffab0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -18,9 +18,10 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> { let is_unsafe = match def { DefWithBodyId::FunctionId(it) => db.function_data(it).has_unsafe_kw(), - DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) | DefWithBodyId::VariantId(_) => { - false - } + DefWithBodyId::StaticId(_) + | DefWithBodyId::ConstId(_) + | DefWithBodyId::VariantId(_) + | DefWithBodyId::InTypeConstId(_) => false, }; if is_unsafe { return res; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index f90e025c7cc..c1df24d1729 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -2,7 +2,10 @@ //! HIR back into source code, and just displaying them for debugging/testing //! purposes. -use std::fmt::{self, Debug}; +use std::{ + fmt::{self, Debug}, + mem::size_of, +}; use base_db::CrateId; use chalk_ir::{BoundVar, TyKind}; @@ -536,8 +539,44 @@ fn render_const_scalar( } f.write_str("]") } + TyKind::Dyn(_) => { + let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap()); + let ty_id = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap()); + let Ok(t) = memory_map.vtable.ty(ty_id) else { + return f.write_str("<ty-missing-in-vtable-map>"); + }; + let Ok(layout) = f.db.layout_of_ty(t.clone(), krate) else { + return f.write_str("<layout-error>"); + }; + let size = layout.size.bytes_usize(); + let Some(bytes) = memory_map.get(addr, size) else { + return f.write_str("<ref-data-not-available>"); + }; + f.write_str("&")?; + render_const_scalar(f, bytes, memory_map, t) + } + TyKind::Adt(adt, _) if b.len() == 2 * size_of::<usize>() => match adt.0 { + hir_def::AdtId::StructId(s) => { + let data = f.db.struct_data(s); + write!(f, "&{}", data.name.display(f.db.upcast()))?; + Ok(()) + } + _ => { + return f.write_str("<unsized-enum-or-union>"); + } + }, _ => { - let addr = usize::from_le_bytes(b.try_into().unwrap()); + let addr = usize::from_le_bytes(match b.try_into() { + Ok(b) => b, + Err(_) => { + never!( + "tried rendering ty {:?} in const ref with incorrect byte count {}", + t, + b.len() + ); + return f.write_str("<layout-error>"); + } + }); let Ok(layout) = f.db.layout_of_ty(t.clone(), krate) else { return f.write_str("<layout-error>"); }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 80f32e96ee6..1ac0837b5b2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -41,10 +41,15 @@ use stdx::{always, never}; use triomphe::Arc; use crate::{ - db::HirDatabase, fold_tys, infer::coerce::CoerceMany, lower::ImplTraitLoweringMode, - static_lifetime, to_assoc_type_id, traits::FnTrait, AliasEq, AliasTy, ClosureId, DomainGoal, - GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, RpitId, Substitution, - TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, + db::HirDatabase, + fold_tys, + infer::coerce::CoerceMany, + lower::ImplTraitLoweringMode, + static_lifetime, to_assoc_type_id, + traits::FnTrait, + utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder}, + AliasEq, AliasTy, ClosureId, DomainGoal, GenericArg, Goal, ImplTraitId, InEnvironment, + Interner, ProjectionTy, RpitId, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, }; // This lint has a false positive here. See the link below for details. @@ -102,6 +107,16 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer }, }); } + DefWithBodyId::InTypeConstId(c) => { + // FIXME(const-generic-body): We should not get the return type in this way. + ctx.return_ty = c + .lookup(db.upcast()) + .thing + .box_any() + .downcast::<InTypeConstIdMetadata>() + .unwrap() + .0; + } } ctx.infer_body(); @@ -684,7 +699,7 @@ impl<'a> InferenceContext<'a> { fn collect_fn(&mut self, func: FunctionId) { let data = self.db.function_data(func); - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, func.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Param); let mut param_tys = data.params.iter().map(|type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>(); @@ -708,7 +723,7 @@ impl<'a> InferenceContext<'a> { } let return_ty = &*data.ret_type; - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); let return_ty = ctx.lower_ty(return_ty); let return_ty = self.insert_type_vars(return_ty); @@ -823,7 +838,7 @@ impl<'a> InferenceContext<'a> { } fn make_ty(&mut self, type_ref: &TypeRef) -> Ty { - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); let ty = ctx.lower_ty(type_ref); let ty = self.insert_type_vars(ty); self.normalize_associated_types_in(ty) @@ -850,7 +865,21 @@ impl<'a> InferenceContext<'a> { } fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { - self.table.unify(ty1, ty2) + let ty1 = ty1 + .clone() + .try_fold_with( + &mut UnevaluatedConstEvaluatorFolder { db: self.db }, + DebruijnIndex::INNERMOST, + ) + .unwrap(); + let ty2 = ty2 + .clone() + .try_fold_with( + &mut UnevaluatedConstEvaluatorFolder { db: self.db }, + DebruijnIndex::INNERMOST, + ) + .unwrap(); + self.table.unify(&ty1, &ty2) } /// Attempts to returns the deeply last field of nested structures, but @@ -973,7 +1002,7 @@ impl<'a> InferenceContext<'a> { Some(path) => path, None => return (self.err_ty(), None), }; - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); let (resolution, unresolved) = if value_ns { match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path) { Some(ResolveValueResult::ValueNs(value)) => match value { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index 23189f383e0..ff64ae252bc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -715,10 +715,9 @@ impl InferenceContext<'_> { } fn is_upvar(&self, place: &HirPlace) -> bool { - let b = &self.body[place.local]; if let Some(c) = self.current_closure { let (_, root) = self.db.lookup_intern_closure(c.into()); - return b.is_upvar(root); + return self.body.is_binding_upvar(place.local, root); } false } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 33e98ac86cf..194471f0048 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -173,8 +173,8 @@ impl<'a> InferenceContext<'a> { } Expr::Const(id) => { self.with_breakable_ctx(BreakableKind::Border, None, None, |this| { - let (_, expr) = this.db.lookup_intern_anonymous_const(*id); - this.infer_expr(expr, expected) + let loc = this.db.lookup_intern_anonymous_const(*id); + this.infer_expr(loc.root, expected) }) .1 } @@ -1715,6 +1715,7 @@ impl<'a> InferenceContext<'a> { const_or_path_to_chalk( this.db, &this.resolver, + this.owner.into(), ty, c, ParamLoweringMode::Placeholder, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs index 44783424390..46f2e1d7d12 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs @@ -43,8 +43,8 @@ impl<'a> InferenceContext<'a> { } } Expr::Const(id) => { - let (_, expr) = self.db.lookup_intern_anonymous_const(*id); - self.infer_mut_expr(expr, Mutability::Not); + let loc = self.db.lookup_intern_anonymous_const(*id); + self.infer_mut_expr(loc.root, Mutability::Not); } Expr::Let { pat, expr } => self.infer_mut_expr(*expr, self.pat_bound_mutability(*pat)), Expr::Block { id: _, statements, tail, label: _ } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs index 95a20f983f1..79d9e21e797 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs @@ -44,7 +44,8 @@ impl InferenceContext<'_> { let last = path.segments().last()?; // Don't use `self.make_ty()` here as we need `orig_ns`. - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); + let ctx = + crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); let (ty, orig_ns) = ctx.lower_ty_ext(type_ref); let ty = self.table.insert_type_vars(ty); let ty = self.table.normalize_associated_types_in(ty); @@ -108,7 +109,7 @@ impl InferenceContext<'_> { } }; - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); let substs = ctx.substs_from_path(path, value_def, true); let substs = substs.as_slice(Interner); let parent_substs = self_subst.or_else(|| { @@ -190,7 +191,11 @@ impl InferenceContext<'_> { (TypeNs::TraitId(trait_), true) => { let segment = remaining_segments.last().expect("there should be at least one segment here"); - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); + let ctx = crate::lower::TyLoweringContext::new( + self.db, + &self.resolver, + self.owner.into(), + ); let trait_ref = ctx.lower_trait_ref_from_resolved_path(trait_, resolved_segment, None); self.resolve_trait_assoc_item(trait_ref, segment, id) @@ -202,7 +207,11 @@ impl InferenceContext<'_> { // as Iterator>::Item::default`) let remaining_segments_for_ty = remaining_segments.take(remaining_segments.len() - 1); - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); + let ctx = crate::lower::TyLoweringContext::new( + self.db, + &self.resolver, + self.owner.into(), + ); let (ty, _) = ctx.lower_partly_resolved_path( def, resolved_segment, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs index 89f7d9c4f4a..e4dd4b86cf9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs @@ -266,7 +266,7 @@ impl chalk_ir::interner::Interner for Interner { c1: &Self::InternedConcreteConst, c2: &Self::InternedConcreteConst, ) -> bool { - (c1 == &ConstScalar::Unknown) || (c2 == &ConstScalar::Unknown) || (c1 == c2) + !matches!(c1, ConstScalar::Bytes(..)) || !matches!(c2, ConstScalar::Bytes(..)) || (c1 == c2) } fn intern_generic_arg( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs index fca2e09ff0a..0ff8c532d47 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use base_db::fixture::WithFixture; use chalk_ir::{AdtId, TyKind}; +use either::Either; use hir_def::db::DefDatabase; use triomphe::Arc; @@ -25,27 +26,38 @@ fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro ); let (db, file_ids) = TestDB::with_many_files(&ra_fixture); - let (adt_id, module_id) = file_ids + let (adt_or_type_alias_id, module_id) = file_ids .into_iter() .find_map(|file_id| { let module_id = db.module_for_file(file_id); let def_map = module_id.def_map(&db); let scope = &def_map[module_id.local_id].scope; - let adt_id = scope.declarations().find_map(|x| match x { + let adt_or_type_alias_id = scope.declarations().find_map(|x| match x { hir_def::ModuleDefId::AdtId(x) => { let name = match x { hir_def::AdtId::StructId(x) => db.struct_data(x).name.to_smol_str(), hir_def::AdtId::UnionId(x) => db.union_data(x).name.to_smol_str(), hir_def::AdtId::EnumId(x) => db.enum_data(x).name.to_smol_str(), }; - (name == "Goal").then_some(x) + (name == "Goal").then_some(Either::Left(x)) + } + hir_def::ModuleDefId::TypeAliasId(x) => { + let name = db.type_alias_data(x).name.to_smol_str(); + (name == "Goal").then_some(Either::Right(x)) } _ => None, })?; - Some((adt_id, module_id)) + Some((adt_or_type_alias_id, module_id)) }) .unwrap(); - let goal_ty = TyKind::Adt(AdtId(adt_id), Substitution::empty(Interner)).intern(Interner); + let goal_ty = match adt_or_type_alias_id { + Either::Left(adt_id) => { + TyKind::Adt(AdtId(adt_id), Substitution::empty(Interner)).intern(Interner) + } + Either::Right(ty_id) => { + db.ty(ty_id.into()).substitute(Interner, &Substitution::empty(Interner)) + } + }; db.layout_of_ty(goal_ty, module_id.krate()) } @@ -380,9 +392,22 @@ fn niche_optimization() { #[test] fn const_eval() { size_and_align! { + struct Goal([i32; 2 + 2]); + } + size_and_align! { const X: usize = 5; struct Goal([i32; X]); } + size_and_align! { + mod foo { + pub(super) const BAR: usize = 5; + } + struct Ar<T>([T; foo::BAR]); + struct Goal(Ar<Ar<i32>>); + } + size_and_align! { + type Goal = [u8; 2 + 2]; + } } #[test] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 0c68891fe49..9951a1c750b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -27,10 +27,11 @@ use hir_def::{ nameres::MacroSubNs, path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, - type_ref::{ConstRefOrPath, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef}, + type_ref::{ConstRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef}, AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, - GenericDefId, HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, StaticId, - StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId, + GenericDefId, HasModule, ImplId, InTypeConstLoc, ItemContainerId, LocalFieldId, Lookup, + ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeOwnerId, + TypeParamId, UnionId, VariantId, }; use hir_expand::{name::Name, ExpandResult}; use intern::Interned; @@ -43,17 +44,24 @@ use triomphe::Arc; use crate::{ all_super_traits, - consteval::{intern_const_ref, path_to_const, unknown_const, unknown_const_as_generic}, + consteval::{ + intern_const_ref, intern_const_scalar, path_to_const, unknown_const, + unknown_const_as_generic, + }, db::HirDatabase, make_binders, mapping::{from_chalk_trait_id, ToChalk}, static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, utils::Generics, - utils::{all_super_trait_refs, associated_type_by_name_including_super_traits, generics}, - AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, DebruijnIndex, DynTy, FnPointer, - FnSig, FnSubst, GenericArgData, ImplTraitId, Interner, ParamKind, PolyFnSig, ProjectionTy, - QuantifiedWhereClause, QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits, - Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause, + utils::{ + all_super_trait_refs, associated_type_by_name_including_super_traits, generics, + InTypeConstIdMetadata, + }, + AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, ConstScalar, DebruijnIndex, DynTy, + FnPointer, FnSig, FnSubst, GenericArgData, ImplTraitId, Interner, ParamKind, PolyFnSig, + ProjectionTy, QuantifiedWhereClause, QuantifiedWhereClauses, ReturnTypeImplTrait, + ReturnTypeImplTraits, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, + TyKind, WhereClause, }; #[derive(Debug)] @@ -106,6 +114,7 @@ pub struct TyLoweringContext<'a> { pub db: &'a dyn HirDatabase, resolver: &'a Resolver, in_binders: DebruijnIndex, + owner: TypeOwnerId, /// Note: Conceptually, it's thinkable that we could be in a location where /// some type params should be represented as placeholders, and others /// should be converted to variables. I think in practice, this isn't @@ -118,13 +127,14 @@ pub struct TyLoweringContext<'a> { } impl<'a> TyLoweringContext<'a> { - pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self { + pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver, owner: TypeOwnerId) -> Self { let impl_trait_mode = ImplTraitLoweringState::Disallowed; let type_param_mode = ParamLoweringMode::Placeholder; let in_binders = DebruijnIndex::INNERMOST; Self { db, resolver, + owner, in_binders, impl_trait_mode, type_param_mode, @@ -235,6 +245,7 @@ impl<'a> TyLoweringContext<'a> { let const_len = const_or_path_to_chalk( self.db, self.resolver, + self.owner, TyBuilder::usize(), len, self.type_param_mode, @@ -840,6 +851,7 @@ impl<'a> TyLoweringContext<'a> { const_or_path_to_chalk( self.db, self.resolver, + self.owner, ty, c, self.type_param_mode, @@ -1356,8 +1368,8 @@ pub(crate) fn field_types_query( }; let generics = generics(db.upcast(), def); let mut res = ArenaMap::default(); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, GenericDefId::from(variant_id.adt_id()).into()) + .with_type_param_mode(ParamLoweringMode::Variable); for (field_id, field_data) in var_data.fields().iter() { res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref))); } @@ -1379,8 +1391,8 @@ pub(crate) fn generic_predicates_for_param_query( assoc_name: Option<Name>, ) -> Arc<[Binders<QuantifiedWhereClause>]> { let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, def.into()) + .with_type_param_mode(ParamLoweringMode::Variable); let generics = generics(db.upcast(), def); let mut predicates: Vec<_> = resolver .where_predicates_in_scope() @@ -1468,8 +1480,8 @@ pub(crate) fn trait_environment_query( def: GenericDefId, ) -> Arc<TraitEnvironment> { let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Placeholder); + let ctx = TyLoweringContext::new(db, &resolver, def.into()) + .with_type_param_mode(ParamLoweringMode::Placeholder); let mut traits_in_scope = Vec::new(); let mut clauses = Vec::new(); for pred in resolver.where_predicates_in_scope() { @@ -1527,8 +1539,8 @@ pub(crate) fn generic_predicates_query( def: GenericDefId, ) -> Arc<[Binders<QuantifiedWhereClause>]> { let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, def.into()) + .with_type_param_mode(ParamLoweringMode::Variable); let generics = generics(db.upcast(), def); let mut predicates = resolver @@ -1582,8 +1594,8 @@ pub(crate) fn generic_defaults_query( def: GenericDefId, ) -> Arc<[Binders<chalk_ir::GenericArg<Interner>>]> { let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, def.into()) + .with_type_param_mode(ParamLoweringMode::Variable); let generic_params = generics(db.upcast(), def); let parent_start_idx = generic_params.len_self(); @@ -1648,11 +1660,11 @@ pub(crate) fn generic_defaults_recover( fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { let data = db.function_data(def); let resolver = def.resolver(db.upcast()); - let ctx_params = TyLoweringContext::new(db, &resolver) + let ctx_params = TyLoweringContext::new(db, &resolver, def.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Variable) .with_type_param_mode(ParamLoweringMode::Variable); let params = data.params.iter().map(|tr| ctx_params.lower_ty(tr)).collect::<Vec<_>>(); - let ctx_ret = TyLoweringContext::new(db, &resolver) + let ctx_ret = TyLoweringContext::new(db, &resolver, def.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) .with_type_param_mode(ParamLoweringMode::Variable); let ret = ctx_ret.lower_ty(&data.ret_type); @@ -1683,8 +1695,8 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders<Ty> { let data = db.const_data(def); let generics = generics(db.upcast(), def.into()); let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, def.into()) + .with_type_param_mode(ParamLoweringMode::Variable); make_binders(db, &generics, ctx.lower_ty(&data.type_ref)) } @@ -1693,7 +1705,7 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders<Ty> { fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders<Ty> { let data = db.static_data(def); let resolver = def.resolver(db.upcast()); - let ctx = TyLoweringContext::new(db, &resolver); + let ctx = TyLoweringContext::new(db, &resolver, def.into()); Binders::empty(Interner, ctx.lower_ty(&data.type_ref)) } @@ -1702,8 +1714,8 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS let struct_data = db.struct_data(def); let fields = struct_data.variant_data.fields(); let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, AdtId::from(def).into()) + .with_type_param_mode(ParamLoweringMode::Variable); let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>(); let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders(); Binders::new(binders, CallableSig::from_params_and_return(params, ret, false, Safety::Safe)) @@ -1715,7 +1727,7 @@ fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Binders<T if let StructKind::Unit = struct_data.variant_data.kind() { return type_for_adt(db, def.into()); } - let generics = generics(db.upcast(), def.into()); + let generics = generics(db.upcast(), AdtId::from(def).into()); let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); make_binders( db, @@ -1729,8 +1741,8 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) let var_data = &enum_data.variants[def.local_id]; let fields = var_data.variant_data.fields(); let resolver = def.parent.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, DefWithBodyId::VariantId(def).into()) + .with_type_param_mode(ParamLoweringMode::Variable); let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>(); let (ret, binders) = type_for_adt(db, def.parent.into()).into_value_and_skipped_binders(); Binders::new(binders, CallableSig::from_params_and_return(params, ret, false, Safety::Safe)) @@ -1762,8 +1774,8 @@ fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> { fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> { let generics = generics(db.upcast(), t.into()); let resolver = t.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, t.into()) + .with_type_param_mode(ParamLoweringMode::Variable); if db.type_alias_data(t).is_extern { Binders::empty(Interner, TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner)) } else { @@ -1884,8 +1896,8 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde "impl_self_ty_query({impl_id:?} -> {impl_loc:?} -> {impl_data:?})" )); let generics = generics(db.upcast(), impl_id.into()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, impl_id.into()) + .with_type_param_mode(ParamLoweringMode::Variable); make_binders(db, &generics, ctx.lower_ty(&impl_data.self_ty)) } @@ -1894,7 +1906,7 @@ pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> T let parent_data = db.generic_params(def.parent()); let data = &parent_data.type_or_consts[def.local_id()]; let resolver = def.parent().resolver(db.upcast()); - let ctx = TyLoweringContext::new(db, &resolver); + let ctx = TyLoweringContext::new(db, &resolver, def.parent().into()); match data { TypeOrConstParamData::TypeParamData(_) => { never!(); @@ -1920,8 +1932,8 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option< let _cx = stdx::panic_context::enter(format!( "impl_trait_query({impl_id:?} -> {impl_loc:?} -> {impl_data:?})" )); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, impl_id.into()) + .with_type_param_mode(ParamLoweringMode::Variable); let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders(); let target_trait = impl_data.target_trait.as_ref()?; Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, Some(self_ty))?)) @@ -1934,7 +1946,7 @@ pub(crate) fn return_type_impl_traits( // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe let data = db.function_data(def); let resolver = def.resolver(db.upcast()); - let ctx_ret = TyLoweringContext::new(db, &resolver) + let ctx_ret = TyLoweringContext::new(db, &resolver, def.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) .with_type_param_mode(ParamLoweringMode::Variable); let _ret = ctx_ret.lower_ty(&data.ret_type); @@ -1969,7 +1981,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( arg: &'a GenericArg, this: &mut T, for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a, - for_const: impl FnOnce(&mut T, &ConstRefOrPath, Ty) -> Const + 'a, + for_const: impl FnOnce(&mut T, &ConstRef, Ty) -> Const + 'a, ) -> Option<crate::GenericArg> { let kind = match kind_id { Either::Left(_) => ParamKind::Type, @@ -1997,7 +2009,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( let p = p.mod_path()?; if p.kind == PathKind::Plain { if let [n] = p.segments() { - let c = ConstRefOrPath::Path(n.clone()); + let c = ConstRef::Path(n.clone()); return Some( GenericArgData::Const(for_const(this, &c, c_ty)).intern(Interner), ); @@ -2013,15 +2025,16 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( pub(crate) fn const_or_path_to_chalk( db: &dyn HirDatabase, resolver: &Resolver, + owner: TypeOwnerId, expected_ty: Ty, - value: &ConstRefOrPath, + value: &ConstRef, mode: ParamLoweringMode, args: impl FnOnce() -> Generics, debruijn: DebruijnIndex, ) -> Const { match value { - ConstRefOrPath::Scalar(s) => intern_const_ref(db, s, expected_ty, resolver.krate()), - ConstRefOrPath::Path(n) => { + ConstRef::Scalar(s) => intern_const_ref(db, s, expected_ty, resolver.krate()), + ConstRef::Path(n) => { let path = ModPath::from_segments(PathKind::Plain, Some(n.clone())); path_to_const( db, @@ -2034,6 +2047,26 @@ pub(crate) fn const_or_path_to_chalk( ) .unwrap_or_else(|| unknown_const(expected_ty)) } + &ConstRef::Complex(it) => { + let crate_data = &db.crate_graph()[owner.module(db.upcast()).krate()]; + if crate_data.env.get("__ra_is_test_fixture").is_none() && crate_data.origin.is_local() + { + // FIXME: current `InTypeConstId` is very unstable, so we only use it in non local crate + // that are unlikely to be edited. + return unknown_const(expected_ty); + } + let c = db + .intern_in_type_const(InTypeConstLoc { + id: it, + owner, + thing: Box::new(InTypeConstIdMetadata(expected_ty.clone())), + }) + .into(); + intern_const_scalar( + ConstScalar::UnevaluatedConst(c, Substitution::empty(Interner)), + expected_ty, + ) + } } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 6fa3d1351a9..ab6430e8f19 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -570,7 +570,7 @@ impl ReceiverAdjustments { .intern(Interner); } } - never!("unsize_array with non-reference-to-array {:?}", ty); + // FIXME: report diagnostic if array unsizing happens without indirection. ty }; adjust.push(Adjustment { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs index a0ea1cc5ef7..a5dd0182eb6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs @@ -240,10 +240,14 @@ fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> Projectio /// Returns a map from basic blocks to the set of locals that might be ever initialized before /// the start of the block. Only `StorageDead` can remove something from this map, and we ignore /// `Uninit` and `drop` and similar after initialization. -fn ever_initialized_map(body: &MirBody) -> ArenaMap<BasicBlockId, ArenaMap<LocalId, bool>> { +fn ever_initialized_map( + db: &dyn HirDatabase, + body: &MirBody, +) -> ArenaMap<BasicBlockId, ArenaMap<LocalId, bool>> { let mut result: ArenaMap<BasicBlockId, ArenaMap<LocalId, bool>> = body.basic_blocks.iter().map(|x| (x.0, ArenaMap::default())).collect(); fn dfs( + db: &dyn HirDatabase, body: &MirBody, b: BasicBlockId, l: LocalId, @@ -267,7 +271,7 @@ fn ever_initialized_map(body: &MirBody) -> ArenaMap<BasicBlockId, ArenaMap<Local } } let Some(terminator) = &block.terminator else { - never!("Terminator should be none only in construction"); + never!("Terminator should be none only in construction.\nThe body:\n{}", body.pretty_print(db)); return; }; let targets = match &terminator.kind { @@ -299,18 +303,18 @@ fn ever_initialized_map(body: &MirBody) -> ArenaMap<BasicBlockId, ArenaMap<Local for target in targets { if !result[target].contains_idx(l) || !result[target][l] && is_ever_initialized { result[target].insert(l, is_ever_initialized); - dfs(body, target, l, result); + dfs(db, body, target, l, result); } } } for &l in &body.param_locals { result[body.start_block].insert(l, true); - dfs(body, body.start_block, l, &mut result); + dfs(db, body, body.start_block, l, &mut result); } for l in body.locals.iter().map(|x| x.0) { if !result[body.start_block].contains_idx(l) { result[body.start_block].insert(l, false); - dfs(body, body.start_block, l, &mut result); + dfs(db, body, body.start_block, l, &mut result); } } result @@ -326,7 +330,7 @@ fn mutability_of_locals( MutabilityReason::Mut { spans } => spans.push(span), x @ MutabilityReason::Not => *x = MutabilityReason::Mut { spans: vec![span] }, }; - let ever_init_maps = ever_initialized_map(body); + let ever_init_maps = ever_initialized_map(db, body); for (block_id, mut ever_init_map) in ever_init_maps.into_iter() { let block = &body.basic_blocks[block_id]; for statement in &block.statements { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index ce14f6dbad5..9acf9d39e56 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -77,7 +77,7 @@ impl VTableMap { id } - fn ty(&self, id: usize) -> Result<&Ty> { + pub(crate) fn ty(&self, id: usize) -> Result<&Ty> { self.id_to_ty.get(id).ok_or(MirEvalError::InvalidVTableId(id)) } @@ -1571,16 +1571,24 @@ impl Evaluator<'_> { } None => { let mut check_inner = None; + let (addr, meta) = bytes.split_at(bytes.len() / 2); let element_size = match t.kind(Interner) { TyKind::Str => 1, TyKind::Slice(t) => { check_inner = Some(t); this.size_of_sized(t, locals, "slice inner type")? } - _ => return Ok(()), // FIXME: support other kind of unsized types + TyKind::Dyn(_) => { + let t = this.vtable_map.ty_of_bytes(meta)?; + check_inner = Some(t); + this.size_of_sized(t, locals, "dyn concrete type")? + } + _ => return Ok(()), + }; + let count = match t.kind(Interner) { + TyKind::Dyn(_) => 1, + _ => from_bytes!(usize, meta), }; - let (addr, meta) = bytes.split_at(bytes.len() / 2); - let count = from_bytes!(usize, meta); let size = element_size * count; let addr = Address::from_bytes(addr)?; let b = this.read_memory(addr, size)?; @@ -1588,7 +1596,7 @@ impl Evaluator<'_> { if let Some(ty) = check_inner { for i in 0..count { let offset = element_size * i; - rec(this, &b[offset..offset + element_size], ty, locals, mm)?; + rec(this, &b[offset..offset + element_size], &ty, locals, mm)?; } } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index aad1a82f298..2cb29b4ab91 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -1853,7 +1853,7 @@ pub fn mir_body_for_closure_query( .result .binding_locals .into_iter() - .filter(|x| ctx.body[x.0].owner == Some(expr)) + .filter(|it| ctx.body.binding_owners.get(&it.0).copied() == Some(expr)) .collect(); if let Some(err) = err { return Err(MirLowerError::UnresolvedUpvar(err)); @@ -1876,6 +1876,7 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result<Arc<Mi DefWithBodyId::VariantId(it) => { db.enum_data(it.parent).variants[it.local_id].name.display(db.upcast()).to_string() } + DefWithBodyId::InTypeConstId(it) => format!("in type const {it:?}"), }); let body = db.body(def); let infer = db.infer(def); @@ -1908,10 +1909,11 @@ pub fn lower_to_mir( // 0 is return local ctx.result.locals.alloc(Local { ty: ctx.expr_ty_after_adjustments(root_expr) }); let binding_picker = |b: BindingId| { + let owner = ctx.body.binding_owners.get(&b).copied(); if root_expr == body.body_expr { - body[b].owner.is_none() + owner.is_none() } else { - body[b].owner == Some(root_expr) + owner == Some(root_expr) } }; // 1 to param_len is for params diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs index 58662b01b99..ac23e77bd2b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs @@ -60,6 +60,9 @@ impl MirBody { let data = db.enum_data(id.parent); w!(this, "enum {} = ", data.name.display(db.upcast())); } + hir_def::DefWithBodyId::InTypeConstId(id) => { + w!(this, "in type const {id:?} = "); + } }); ctx.result } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs index 2db04024b7b..85714128006 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -146,6 +146,7 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour let loc = db.lookup_intern_enum(it.parent); loc.source(&db).value.syntax().text_range().start() } + DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(), }); let mut unexpected_type_mismatches = String::new(); for def in defs { @@ -391,6 +392,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { let loc = db.lookup_intern_enum(it.parent); loc.source(&db).value.syntax().text_range().start() } + DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(), }); for def in defs { let (body, source_map) = db.body_with_source_map(def); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index f18c953a7af..047900a324e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -1955,3 +1955,26 @@ impl Inner<1> { "#, ); } + +#[test] +fn dont_crash_on_slice_unsizing() { + check_no_mismatches( + r#" +//- minicore: slice, unsize, coerce_unsized +trait Tr { + fn f(self); +} + +impl Tr for [i32] { + fn f(self) { + let t; + x(t); + } +} + +fn x(a: [i32; 4]) { + let b = a.f(); +} + "#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index 3ece40486dd..a0ff628435f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -1829,6 +1829,38 @@ impl Foo for u8 { } #[test] +fn const_eval_in_function_signature() { + check_types( + r#" +const fn foo() -> usize { + 5 +} + +fn f() -> [u8; foo()] { + loop {} +} + +fn main() { + let t = f(); + //^ [u8; 5] +}"#, + ); + check_types( + r#" +//- minicore: default, builtin_impls +fn f() -> [u8; Default::default()] { + loop {} +} + +fn main() { + let t = f(); + //^ [u8; 0] +} + "#, + ); +} + +#[test] fn shadowing_primitive_with_inner_items() { check_types( r#" @@ -3465,6 +3497,22 @@ fn func() { ); } +#[test] +fn pointee_trait() { + check_types( + r#" +//- minicore: pointee +use core::ptr::Pointee; +fn func() { + let x: <u8 as Pointee>::Metadata; + //^ () + let x: <[u8] as Pointee>::Metadata; + //^ usize +} + "#, + ); +} + // FIXME #[test] fn castable_to() { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 829a6ab189e..97ae732a904 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -4335,8 +4335,9 @@ fn derive_macro_bounds() { #[derive(Clone)] struct AssocGeneric<T: Tr>(T::Assoc); - #[derive(Clone)] - struct AssocGeneric2<T: Tr>(<T as Tr>::Assoc); + // Currently rustc does not accept this. + // #[derive(Clone)] + // struct AssocGeneric2<T: Tr>(<T as Tr>::Assoc); #[derive(Clone)] struct AssocGeneric3<T: Tr>(Generic<T::Assoc>); @@ -4361,9 +4362,8 @@ fn derive_macro_bounds() { let x: &AssocGeneric<Copy> = &AssocGeneric(NotCopy); let x = x.clone(); //^ &AssocGeneric<Copy> - let x: &AssocGeneric2<Copy> = &AssocGeneric2(NotCopy); - let x = x.clone(); - //^ &AssocGeneric2<Copy> + // let x: &AssocGeneric2<Copy> = &AssocGeneric2(NotCopy); + // let x = x.clone(); let x: &AssocGeneric3<Copy> = &AssocGeneric3(Generic(NotCopy)); let x = x.clone(); //^ &AssocGeneric3<Copy> diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 681d087ede6..3636580630d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -1,7 +1,7 @@ //! Helper functions for working with def, which don't need to be a separate //! query, but can't be computed directly from `*Data` (ie, which need a `db`). -use std::iter; +use std::{hash::Hash, iter}; use base_db::CrateId; use chalk_ir::{ @@ -20,7 +20,8 @@ use hir_def::{ resolver::{HasResolver, TypeNs}, type_ref::{TraitBoundModifier, TypeRef}, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, ItemContainerId, - LocalEnumVariantId, Lookup, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, + LocalEnumVariantId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId, TypeOrConstParamId, + TypeParamId, }; use hir_expand::name::Name; use intern::Interned; @@ -464,3 +465,28 @@ pub(crate) fn detect_variant_from_bytes<'a>( }; Some((var_id, var_layout)) } + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub(crate) struct InTypeConstIdMetadata(pub(crate) Ty); + +impl OpaqueInternableThing for InTypeConstIdMetadata { + fn dyn_hash(&self, mut state: &mut dyn std::hash::Hasher) { + self.hash(&mut state); + } + + fn dyn_eq(&self, other: &dyn OpaqueInternableThing) -> bool { + other.as_any().downcast_ref::<Self>().map_or(false, |x| self == x) + } + + fn dyn_clone(&self) -> Box<dyn OpaqueInternableThing> { + Box::new(self.clone()) + } + + fn as_any(&self) -> &dyn std::any::Any { + self + } + + fn box_any(&self) -> Box<dyn std::any::Any> { + Box::new(self.clone()) + } +} diff --git a/src/tools/rust-analyzer/crates/hir/src/from_id.rs b/src/tools/rust-analyzer/crates/hir/src/from_id.rs index 883e6a29b06..de23902199f 100644 --- a/src/tools/rust-analyzer/crates/hir/src/from_id.rs +++ b/src/tools/rust-analyzer/crates/hir/src/from_id.rs @@ -40,6 +40,7 @@ from_id![ (hir_def::TraitAliasId, crate::TraitAlias), (hir_def::StaticId, crate::Static), (hir_def::ConstId, crate::Const), + (hir_def::InTypeConstId, crate::InTypeConst), (hir_def::FunctionId, crate::Function), (hir_def::ImplId, crate::Impl), (hir_def::TypeOrConstParamId, crate::TypeOrConstParam), @@ -144,6 +145,7 @@ impl From<DefWithBody> for DefWithBodyId { DefWithBody::Static(it) => DefWithBodyId::StaticId(it.id), DefWithBody::Const(it) => DefWithBodyId::ConstId(it.id), DefWithBody::Variant(it) => DefWithBodyId::VariantId(it.into()), + DefWithBody::InTypeConst(it) => DefWithBodyId::InTypeConstId(it.id), } } } @@ -155,6 +157,7 @@ impl From<DefWithBodyId> for DefWithBody { DefWithBodyId::StaticId(it) => DefWithBody::Static(it.into()), DefWithBodyId::ConstId(it) => DefWithBody::Const(it.into()), DefWithBodyId::VariantId(it) => DefWithBody::Variant(it.into()), + DefWithBodyId::InTypeConstId(it) => DefWithBody::InTypeConst(it.into()), } } } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 5926d865421..6df625380ff 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -52,9 +52,10 @@ use hir_def::{ resolver::{HasResolver, Resolver}, src::HasSource as _, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, - EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId, - LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId, - TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, + EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, InTypeConstId, ItemContainerId, + LifetimeParamId, LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, + StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, + UnionId, }; use hir_expand::{name::name, MacroCallKind}; use hir_ty::{ @@ -202,7 +203,7 @@ impl Crate { pub fn root_module(self, db: &dyn HirDatabase) -> Module { let def_map = db.crate_def_map(self.id); - Module { id: def_map.module_id(DefMap::ROOT) } + Module { id: def_map.crate_root().into() } } pub fn modules(self, db: &dyn HirDatabase) -> Vec<Module> { @@ -475,7 +476,7 @@ impl Module { /// in the module tree of any target in `Cargo.toml`. pub fn crate_root(self, db: &dyn HirDatabase) -> Module { let def_map = db.crate_def_map(self.id.krate()); - Module { id: def_map.module_id(DefMap::ROOT) } + Module { id: def_map.crate_root().into() } } pub fn is_crate_root(self) -> bool { @@ -1375,8 +1376,9 @@ pub enum DefWithBody { Static(Static), Const(Const), Variant(Variant), + InTypeConst(InTypeConst), } -impl_from!(Function, Const, Static, Variant for DefWithBody); +impl_from!(Function, Const, Static, Variant, InTypeConst for DefWithBody); impl DefWithBody { pub fn module(self, db: &dyn HirDatabase) -> Module { @@ -1385,6 +1387,7 @@ impl DefWithBody { DefWithBody::Function(f) => f.module(db), DefWithBody::Static(s) => s.module(db), DefWithBody::Variant(v) => v.module(db), + DefWithBody::InTypeConst(c) => c.module(db), } } @@ -1394,6 +1397,7 @@ impl DefWithBody { DefWithBody::Static(s) => Some(s.name(db)), DefWithBody::Const(c) => c.name(db), DefWithBody::Variant(v) => Some(v.name(db)), + DefWithBody::InTypeConst(_) => None, } } @@ -1404,6 +1408,11 @@ impl DefWithBody { DefWithBody::Static(it) => it.ty(db), DefWithBody::Const(it) => it.ty(db), DefWithBody::Variant(it) => it.parent.variant_body_ty(db), + DefWithBody::InTypeConst(it) => Type::new_with_resolver_inner( + db, + &DefWithBodyId::from(it.id).resolver(db.upcast()), + TyKind::Error.intern(Interner), + ), } } @@ -1413,6 +1422,7 @@ impl DefWithBody { DefWithBody::Static(it) => it.id.into(), DefWithBody::Const(it) => it.id.into(), DefWithBody::Variant(it) => it.into(), + DefWithBody::InTypeConst(it) => it.id.into(), } } @@ -1797,6 +1807,8 @@ impl DefWithBody { DefWithBody::Static(it) => it.into(), DefWithBody::Const(it) => it.into(), DefWithBody::Variant(it) => it.into(), + // FIXME: don't ignore diagnostics for in type const + DefWithBody::InTypeConst(_) => return, }; for diag in hir_ty::diagnostics::incorrect_case(db, krate, def.into()) { acc.push(diag.into()) @@ -2086,6 +2098,17 @@ impl HasVisibility for Function { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct InTypeConst { + pub(crate) id: InTypeConstId, +} + +impl InTypeConst { + pub fn module(self, db: &dyn HirDatabase) -> Module { + Module { id: self.id.lookup(db.upcast()).owner.module(db.upcast()) } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Const { pub(crate) id: ConstId, } @@ -2515,7 +2538,7 @@ impl AsAssocItem for DefWithBody { match self { DefWithBody::Function(it) => it.as_assoc_item(db), DefWithBody::Const(it) => it.as_assoc_item(db), - DefWithBody::Static(_) | DefWithBody::Variant(_) => None, + DefWithBody::Static(_) | DefWithBody::Variant(_) | DefWithBody::InTypeConst(_) => None, } } } @@ -2641,14 +2664,22 @@ impl GenericDef { Either::Right(x) => GenericParam::TypeParam(x), } }); - let lt_params = generics + self.lifetime_params(db) + .into_iter() + .map(GenericParam::LifetimeParam) + .chain(ty_params) + .collect() + } + + pub fn lifetime_params(self, db: &dyn HirDatabase) -> Vec<LifetimeParam> { + let generics = db.generic_params(self.into()); + generics .lifetimes .iter() .map(|(local_id, _)| LifetimeParam { id: LifetimeParamId { parent: self.into(), local_id }, }) - .map(GenericParam::LifetimeParam); - lt_params.chain(ty_params).collect() + .collect() } pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> { @@ -2769,6 +2800,22 @@ impl Local { /// All definitions for this local. Example: `let (a$0, _) | (_, a$0) = x;` pub fn sources(self, db: &dyn HirDatabase) -> Vec<LocalSource> { let (body, source_map) = db.body_with_source_map(self.parent); + self.sources_(db, &body, &source_map).collect() + } + + /// The leftmost definition for this local. Example: `let (a$0, _) | (_, a) = x;` + pub fn primary_source(self, db: &dyn HirDatabase) -> LocalSource { + let (body, source_map) = db.body_with_source_map(self.parent); + let src = self.sources_(db, &body, &source_map).next().unwrap(); + src + } + + fn sources_<'a>( + self, + db: &'a dyn HirDatabase, + body: &'a hir_def::body::Body, + source_map: &'a hir_def::body::BodySourceMap, + ) -> impl Iterator<Item = LocalSource> + 'a { body[self.binding_id] .definitions .iter() @@ -2781,14 +2828,7 @@ impl Local { Either::Right(it) => Either::Right(it.to_node(&root)), }) }) - .map(|source| LocalSource { local: self, source }) - .collect() - } - - /// The leftmost definition for this local. Example: `let (a$0, _) | (_, a) = x;` - pub fn primary_source(self, db: &dyn HirDatabase) -> LocalSource { - let all_sources = self.sources(db); - all_sources.into_iter().next().unwrap() + .map(move |source| LocalSource { local: self, source }) } } @@ -3494,6 +3534,14 @@ impl Type { } } + pub fn is_scalar(&self) -> bool { + matches!(self.ty.kind(Interner), TyKind::Scalar(_)) + } + + pub fn is_tuple(&self) -> bool { + matches!(self.ty.kind(Interner), TyKind::Tuple(..)) + } + pub fn remove_ref(&self) -> Option<Type> { match &self.ty.kind(Interner) { TyKind::Ref(.., ty) => Some(self.derived(ty.clone())), @@ -3779,14 +3827,16 @@ impl Type { } } - pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a { + /// Returns types that this type dereferences to (including this type itself). The returned + /// iterator won't yield the same type more than once even if the deref chain contains a cycle. + pub fn autoderef(&self, db: &dyn HirDatabase) -> impl Iterator<Item = Type> + '_ { self.autoderef_(db).map(move |ty| self.derived(ty)) } - fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Ty> + 'a { + fn autoderef_(&self, db: &dyn HirDatabase) -> impl Iterator<Item = Ty> { // There should be no inference vars in types passed here let canonical = hir_ty::replace_errors_with_variables(&self.ty); - autoderef(db, self.env.clone(), canonical).map(|canonical| canonical.value) + autoderef(db, self.env.clone(), canonical) } // This would be nicer if it just returned an iterator, but that runs into diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 2d2b00b147e..5a76a9185a2 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -483,10 +483,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.scope_at_offset(node, offset) } - pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> { - self.imp.scope_for_def(def) - } - pub fn assert_contains_node(&self, node: &SyntaxNode) { self.imp.assert_contains_node(node) } @@ -1074,8 +1070,12 @@ impl<'db> SemanticsImpl<'db> { fn resolve_type(&self, ty: &ast::Type) -> Option<Type> { let analyze = self.analyze(ty.syntax())?; let ctx = LowerCtx::with_file_id(self.db.upcast(), analyze.file_id); - let ty = hir_ty::TyLoweringContext::new(self.db, &analyze.resolver) - .lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone())); + let ty = hir_ty::TyLoweringContext::new( + self.db, + &analyze.resolver, + analyze.resolver.module().into(), + ) + .lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone())); Some(Type::new_with_resolver(self.db, &analyze.resolver, ty)) } @@ -1307,12 +1307,6 @@ impl<'db> SemanticsImpl<'db> { ) } - fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> { - let file_id = self.db.lookup_intern_trait(def.id).id.file_id(); - let resolver = def.id.resolver(self.db.upcast()); - SemanticsScope { db: self.db, file_id, resolver } - } - fn source<Def: HasSource>(&self, def: Def) -> Option<InFile<Def::Ast>> where Def::Ast: AstNode, diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 1374fa332c6..ecb1b306a66 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -38,8 +38,8 @@ use hir_ty::{ UnsafeExpr, }, lang_items::lang_items_for_bin_op, - method_resolution::{self}, - Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, TyLoweringContext, + method_resolution, Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, + TyLoweringContext, }; use itertools::Itertools; use smallvec::SmallVec; @@ -978,7 +978,8 @@ fn resolve_hir_path_( let types = || { let (ty, unresolved) = match path.type_anchor() { Some(type_ref) => { - let (_, res) = TyLoweringContext::new(db, resolver).lower_ty_ext(type_ref); + let (_, res) = TyLoweringContext::new(db, resolver, resolver.module().into()) + .lower_ty_ext(type_ref); res.map(|ty_ns| (ty_ns, path.segments().first())) } None => { diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs index 207e8206c92..43d957412bc 100644 --- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs +++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs @@ -233,6 +233,7 @@ impl<'a> SymbolCollector<'a> { DefWithBodyId::VariantId(id) => { Some(self.db.enum_data(id.parent).variants[id.local_id].name.to_smol_str()) } + DefWithBodyId::InTypeConstId(_) => Some("in type const".into()), } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 6340feda452..d07c6372628 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -1,13 +1,9 @@ use hir::HasSource; -use ide_db::syntax_helpers::insert_whitespace_into_node::insert_ws_into; use syntax::ast::{self, make, AstNode}; use crate::{ assist_context::{AssistContext, Assists}, - utils::{ - add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body, render_snippet, - Cursor, DefaultMethods, - }, + utils::{add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body, DefaultMethods}, AssistId, AssistKind, }; @@ -130,50 +126,36 @@ fn add_missing_impl_members_inner( } let target = impl_def.syntax().text_range(); - acc.add(AssistId(assist_id, AssistKind::QuickFix), label, target, |builder| { - let missing_items = missing_items - .into_iter() - .map(|it| { - if ctx.sema.hir_file_for(it.syntax()).is_macro() { - if let Some(it) = ast::AssocItem::cast(insert_ws_into(it.syntax().clone())) { - return it; - } - } - it.clone_for_update() - }) - .collect(); - let (new_impl_def, first_new_item) = add_trait_assoc_items_to_impl( + acc.add(AssistId(assist_id, AssistKind::QuickFix), label, target, |edit| { + let new_impl_def = edit.make_mut(impl_def.clone()); + let first_new_item = add_trait_assoc_items_to_impl( &ctx.sema, - missing_items, + &missing_items, trait_, - impl_def.clone(), + &new_impl_def, target_scope, ); - match ctx.config.snippet_cap { - None => builder.replace(target, new_impl_def.to_string()), - Some(cap) => { - let mut cursor = Cursor::Before(first_new_item.syntax()); - let placeholder; - if let DefaultMethods::No = mode { - if let ast::AssocItem::Fn(func) = &first_new_item { - if try_gen_trait_body(ctx, func, trait_ref, &impl_def).is_none() { - if let Some(m) = - func.syntax().descendants().find_map(ast::MacroCall::cast) - { - if m.syntax().text() == "todo!()" { - placeholder = m; - cursor = Cursor::Replace(placeholder.syntax()); - } + + if let Some(cap) = ctx.config.snippet_cap { + let mut placeholder = None; + if let DefaultMethods::No = mode { + if let ast::AssocItem::Fn(func) = &first_new_item { + if try_gen_trait_body(ctx, func, trait_ref, &impl_def).is_none() { + if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) + { + if m.syntax().text() == "todo!()" { + placeholder = Some(m); } } } } - builder.replace_snippet( - cap, - target, - render_snippet(cap, new_impl_def.syntax(), cursor), - ) } + + if let Some(macro_call) = placeholder { + edit.add_placeholder_snippet(cap, macro_call); + } else { + edit.add_tabstop_before(cap, first_new_item); + }; }; }) } @@ -366,6 +348,125 @@ impl<U> Foo<U> for S { } #[test] + fn test_lifetime_substitution() { + check_assist( + add_missing_impl_members, + r#" +pub trait Trait<'a, 'b, A, B, C> { + fn foo(&self, one: &'a A, anoter: &'b B) -> &'a C; +} + +impl<'x, 'y, T, V, U> Trait<'x, 'y, T, V, U> for () {$0}"#, + r#" +pub trait Trait<'a, 'b, A, B, C> { + fn foo(&self, one: &'a A, anoter: &'b B) -> &'a C; +} + +impl<'x, 'y, T, V, U> Trait<'x, 'y, T, V, U> for () { + fn foo(&self, one: &'x T, anoter: &'y V) -> &'x U { + ${0:todo!()} + } +}"#, + ); + } + + #[test] + fn test_lifetime_substitution_with_body() { + check_assist( + add_missing_default_members, + r#" +pub trait Trait<'a, 'b, A, B, C: Default> { + fn foo(&self, _one: &'a A, _anoter: &'b B) -> (C, &'a i32) { + let value: &'a i32 = &0; + (C::default(), value) + } +} + +impl<'x, 'y, T, V, U: Default> Trait<'x, 'y, T, V, U> for () {$0}"#, + r#" +pub trait Trait<'a, 'b, A, B, C: Default> { + fn foo(&self, _one: &'a A, _anoter: &'b B) -> (C, &'a i32) { + let value: &'a i32 = &0; + (C::default(), value) + } +} + +impl<'x, 'y, T, V, U: Default> Trait<'x, 'y, T, V, U> for () { + $0fn foo(&self, _one: &'x T, _anoter: &'y V) -> (U, &'x i32) { + let value: &'x i32 = &0; + (<U>::default(), value) + } +}"#, + ); + } + + #[test] + fn test_const_substitution() { + check_assist( + add_missing_default_members, + r#" +struct Bar<const: N: bool> { + bar: [i32, N] +} + +trait Foo<const N: usize, T> { + fn get_n_sq(&self, arg: &T) -> usize { N * N } + fn get_array(&self, arg: Bar<N>) -> [i32; N] { [1; N] } +} + +struct S<T> { + wrapped: T +} + +impl<const X: usize, Y, Z> Foo<X, Z> for S<Y> { + $0 +}"#, + r#" +struct Bar<const: N: bool> { + bar: [i32, N] +} + +trait Foo<const N: usize, T> { + fn get_n_sq(&self, arg: &T) -> usize { N * N } + fn get_array(&self, arg: Bar<N>) -> [i32; N] { [1; N] } +} + +struct S<T> { + wrapped: T +} + +impl<const X: usize, Y, Z> Foo<X, Z> for S<Y> { + $0fn get_n_sq(&self, arg: &Z) -> usize { X * X } + + fn get_array(&self, arg: Bar<X>) -> [i32; X] { [1; X] } +}"#, + ) + } + + #[test] + fn test_const_substitution_2() { + check_assist( + add_missing_default_members, + r#" +trait Foo<const N: usize, const M: usize, T> { + fn get_sum(&self, arg: &T) -> usize { N + M } +} + +impl<X> Foo<42, {20 + 22}, X> for () { + $0 +}"#, + r#" +trait Foo<const N: usize, const M: usize, T> { + fn get_sum(&self, arg: &T) -> usize { N + M } +} + +impl<X> Foo<42, {20 + 22}, X> for () { + $0fn get_sum(&self, arg: &X) -> usize { 42 + {20 + 22} } +}"#, + ) + } + + #[test] fn test_cursor_after_empty_impl_def() { check_assist( add_missing_impl_members, @@ -747,6 +848,115 @@ impl Foo<T> for S<T> { } #[test] + fn test_qualify_generic_default_parameter() { + check_assist( + add_missing_impl_members, + r#" +mod m { + pub struct S; + pub trait Foo<T = S> { + fn bar(&self, other: &T); + } +} + +struct S; +impl m::Foo for S { $0 }"#, + r#" +mod m { + pub struct S; + pub trait Foo<T = S> { + fn bar(&self, other: &T); + } +} + +struct S; +impl m::Foo for S { + fn bar(&self, other: &m::S) { + ${0:todo!()} + } +}"#, + ) + } + + #[test] + fn test_qualify_generic_default_parameter_2() { + check_assist( + add_missing_impl_members, + r#" +mod m { + pub struct Wrapper<T, V> { + one: T, + another: V + }; + pub struct S; + pub trait Foo<T = Wrapper<S, bool>> { + fn bar(&self, other: &T); + } +} + +struct S; +impl m::Foo for S { $0 }"#, + r#" +mod m { + pub struct Wrapper<T, V> { + one: T, + another: V + }; + pub struct S; + pub trait Foo<T = Wrapper<S, bool>> { + fn bar(&self, other: &T); + } +} + +struct S; +impl m::Foo for S { + fn bar(&self, other: &m::Wrapper<m::S, bool>) { + ${0:todo!()} + } +}"#, + ); + } + + #[test] + fn test_qualify_generic_default_parameter_3() { + check_assist( + add_missing_impl_members, + r#" +mod m { + pub struct Wrapper<T, V> { + one: T, + another: V + }; + pub struct S; + pub trait Foo<T = S, V = Wrapper<T, S>> { + fn bar(&self, other: &V); + } +} + +struct S; +impl m::Foo for S { $0 }"#, + r#" +mod m { + pub struct Wrapper<T, V> { + one: T, + another: V + }; + pub struct S; + pub trait Foo<T = S, V = Wrapper<T, S>> { + fn bar(&self, other: &V); + } +} + +struct S; +impl m::Foo for S { + fn bar(&self, other: &m::Wrapper<m::S, m::S>) { + ${0:todo!()} + } +}"#, + ); + } + + #[test] fn test_assoc_type_bounds_are_removed() { check_assist( add_missing_impl_members, @@ -1683,4 +1893,77 @@ impl m::Foo for S { }"#, ) } + + #[test] + fn nested_macro_should_not_cause_crash() { + check_assist( + add_missing_impl_members, + r#" +macro_rules! ty { () => { i32 } } +trait SomeTrait { type Output; } +impl SomeTrait for i32 { type Output = i64; } +macro_rules! define_method { + () => { + fn method(&mut self, params: <ty!() as SomeTrait>::Output); + }; +} +trait AnotherTrait { define_method!(); } +impl $0AnotherTrait for () { +} +"#, + r#" +macro_rules! ty { () => { i32 } } +trait SomeTrait { type Output; } +impl SomeTrait for i32 { type Output = i64; } +macro_rules! define_method { + () => { + fn method(&mut self, params: <ty!() as SomeTrait>::Output); + }; +} +trait AnotherTrait { define_method!(); } +impl AnotherTrait for () { + $0fn method(&mut self,params: <ty!()as SomeTrait>::Output) { + todo!() + } +} +"#, + ); + } + + // FIXME: `T` in `ty!(T)` should be replaced by `PathTransform`. + #[test] + fn paths_in_nested_macro_should_get_transformed() { + check_assist( + add_missing_impl_members, + r#" +macro_rules! ty { ($me:ty) => { $me } } +trait SomeTrait { type Output; } +impl SomeTrait for i32 { type Output = i64; } +macro_rules! define_method { + ($t:ty) => { + fn method(&mut self, params: <ty!($t) as SomeTrait>::Output); + }; +} +trait AnotherTrait<T: SomeTrait> { define_method!(T); } +impl $0AnotherTrait<i32> for () { +} +"#, + r#" +macro_rules! ty { ($me:ty) => { $me } } +trait SomeTrait { type Output; } +impl SomeTrait for i32 { type Output = i64; } +macro_rules! define_method { + ($t:ty) => { + fn method(&mut self, params: <ty!($t) as SomeTrait>::Output); + }; +} +trait AnotherTrait<T: SomeTrait> { define_method!(T); } +impl AnotherTrait<i32> for () { + $0fn method(&mut self,params: <ty!(T)as SomeTrait>::Output) { + todo!() + } +} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs index b310c2db9fa..b6e7d6209c9 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs @@ -1,6 +1,9 @@ use either::Either; use ide_db::syntax_helpers::node_ext::walk_ty; -use syntax::ast::{self, edit::IndentLevel, make, AstNode, HasGenericParams, HasName}; +use syntax::{ + ast::{self, edit::IndentLevel, make, AstNode, HasGenericParams, HasName}, + ted, +}; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -34,14 +37,16 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> || item.syntax(), |impl_| impl_.as_ref().either(AstNode::syntax, AstNode::syntax), ); - let insert_pos = node.text_range().start(); let target = ty.syntax().text_range(); acc.add( AssistId("extract_type_alias", AssistKind::RefactorExtract), "Extract type as type alias", target, - |builder| { + |edit| { + let node = edit.make_syntax_mut(node.clone()); + let target_ty = edit.make_mut(ty.clone()); + let mut known_generics = match item.generic_param_list() { Some(it) => it.generic_params().collect(), None => Vec::new(), @@ -56,27 +61,29 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> let generic_params = generics.map(|it| make::generic_param_list(it.into_iter().cloned())); + // Replace original type with the alias let ty_args = generic_params .as_ref() .map_or(String::new(), |it| it.to_generic_args().to_string()); - let replacement = format!("Type{ty_args}"); - builder.replace(target, replacement); - - let indent = IndentLevel::from_node(node); - let generic_params = generic_params.map_or(String::new(), |it| it.to_string()); - match ctx.config.snippet_cap { - Some(cap) => { - builder.insert_snippet( - cap, - insert_pos, - format!("type $0Type{generic_params} = {ty};\n\n{indent}"), - ); - } - None => { - builder.insert( - insert_pos, - format!("type Type{generic_params} = {ty};\n\n{indent}"), - ); + // FIXME: replace with a `ast::make` constructor + let new_ty = make::ty(&format!("Type{ty_args}")).clone_for_update(); + ted::replace(target_ty.syntax(), new_ty.syntax()); + + // Insert new alias + let indent = IndentLevel::from_node(&node); + let ty_alias = make::ty_alias("Type", generic_params, None, None, Some((ty, None))) + .clone_for_update(); + ted::insert_all( + ted::Position::before(node), + vec![ + ty_alias.syntax().clone().into(), + make::tokens::whitespace(&format!("\n\n{indent}")).into(), + ], + ); + + if let Some(cap) = ctx.config.snippet_cap { + if let Some(name) = ty_alias.name() { + edit.add_tabstop_before(cap, name); } } }, @@ -151,7 +158,7 @@ fn collect_used_generics<'gp>( .and_then(|lt| known_generics.iter().find(find_lifetime(<.text()))), ), ast::Type::ArrayType(ar) => { - if let Some(ast::Expr::PathExpr(p)) = ar.expr() { + if let Some(ast::Expr::PathExpr(p)) = ar.const_arg().and_then(|x| x.expr()) { if let Some(path) = p.path() { if let Some(name_ref) = path.as_single_name_ref() { if let Some(param) = known_generics.iter().find(|gp| { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs index 3667fc375b4..b68c766e647 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs @@ -72,29 +72,27 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' let krate = ty.krate(ctx.db()); ty.iterate_assoc_items(ctx.db(), krate, |item| { if let hir::AssocItem::Function(f) = item { + let name = f.name(ctx.db()); if f.self_param(ctx.db()).is_some() && f.is_visible_from(ctx.db(), current_module) - && seen_names.insert(f.name(ctx.db())) + && seen_names.insert(name.clone()) { - methods.push(f) + methods.push((name, f)) } } Option::<()>::None }); } - - for method in methods { + methods.sort_by(|(a, _), (b, _)| a.cmp(b)); + for (name, method) in methods { let adt = ast::Adt::Struct(strukt.clone()); - let name = method.name(ctx.db()).display(ctx.db()).to_string(); + let name = name.display(ctx.db()).to_string(); // if `find_struct_impl` returns None, that means that a function named `name` already exists. - let Some(impl_def) = find_struct_impl(ctx, &adt, &[name]) else { continue; }; + let Some(impl_def) = find_struct_impl(ctx, &adt, std::slice::from_ref(&name)) else { continue; }; acc.add_group( &GroupLabel("Generate delegate methods…".to_owned()), AssistId("generate_delegate_methods", AssistKind::Generate), - format!( - "Generate delegate for `{field_name}.{}()`", - method.name(ctx.db()).display(ctx.db()) - ), + format!("Generate delegate for `{field_name}.{name}()`",), target, |builder| { // Create the function @@ -102,9 +100,8 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' Some(source) => source.value, None => return, }; - let method_name = method.name(ctx.db()); let vis = method_source.visibility(); - let name = make::name(&method.name(ctx.db()).display(ctx.db()).to_string()); + let fn_name = make::name(&name); let params = method_source.param_list().unwrap_or_else(|| make::param_list(None, [])); let type_params = method_source.generic_param_list(); @@ -114,7 +111,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' }; let tail_expr = make::expr_method_call( make::ext::field_from_idents(["self", &field_name]).unwrap(), // This unwrap is ok because we have at least 1 arg in the list - make::name_ref(&method_name.display(ctx.db()).to_string()), + make::name_ref(&name), arg_list, ); let ret_type = method_source.ret_type(); @@ -126,7 +123,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' let body = make::block_expr([], Some(tail_expr_finished)); let f = make::fn_( vis, - name, + fn_name, type_params, None, params, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs index 850be21c300..c579f6780db 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs @@ -291,12 +291,9 @@ impl FunctionBuilder { let await_expr = call.syntax().parent().and_then(ast::AwaitExpr::cast); let is_async = await_expr.is_some(); - let (ret_type, should_focus_return_type) = make_return_type( - ctx, - &ast::Expr::CallExpr(call.clone()), - target_module, - &mut necessary_generic_params, - ); + let expr_for_ret_ty = await_expr.map_or_else(|| call.clone().into(), |it| it.into()); + let (ret_type, should_focus_return_type) = + make_return_type(ctx, &expr_for_ret_ty, target_module, &mut necessary_generic_params); let (generic_param_list, where_clause) = fn_generic_params(ctx, necessary_generic_params, &target)?; @@ -338,12 +335,9 @@ impl FunctionBuilder { let await_expr = call.syntax().parent().and_then(ast::AwaitExpr::cast); let is_async = await_expr.is_some(); - let (ret_type, should_focus_return_type) = make_return_type( - ctx, - &ast::Expr::MethodCallExpr(call.clone()), - target_module, - &mut necessary_generic_params, - ); + let expr_for_ret_ty = await_expr.map_or_else(|| call.clone().into(), |it| it.into()); + let (ret_type, should_focus_return_type) = + make_return_type(ctx, &expr_for_ret_ty, target_module, &mut necessary_generic_params); let (generic_param_list, where_clause) = fn_generic_params(ctx, necessary_generic_params, &target)?; @@ -429,12 +423,12 @@ impl FunctionBuilder { /// user can change the `todo!` function body. fn make_return_type( ctx: &AssistContext<'_>, - call: &ast::Expr, + expr: &ast::Expr, target_module: Module, necessary_generic_params: &mut FxHashSet<hir::GenericParam>, ) -> (Option<ast::RetType>, bool) { let (ret_ty, should_focus_return_type) = { - match ctx.sema.type_of_expr(call).map(TypeInfo::original) { + match ctx.sema.type_of_expr(expr).map(TypeInfo::original) { Some(ty) if ty.is_unknown() => (Some(make::ty_placeholder()), true), None => (Some(make::ty_placeholder()), true), Some(ty) if ty.is_unit() => (None, false), @@ -2268,13 +2262,13 @@ impl Foo { check_assist( generate_function, r" -fn foo() { - $0bar(42).await(); +async fn foo() { + $0bar(42).await; } ", r" -fn foo() { - bar(42).await(); +async fn foo() { + bar(42).await; } async fn bar(arg: i32) ${0:-> _} { @@ -2285,6 +2279,28 @@ async fn bar(arg: i32) ${0:-> _} { } #[test] + fn return_type_for_async_fn() { + check_assist( + generate_function, + r" +//- minicore: result +async fn foo() { + if Err(()) = $0bar(42).await {} +} +", + r" +async fn foo() { + if Err(()) = bar(42).await {} +} + +async fn bar(arg: i32) -> Result<_, ()> { + ${0:todo!()} +} +", + ); + } + + #[test] fn create_method() { check_assist( generate_function, @@ -2402,6 +2418,31 @@ fn foo() {S.bar();} } #[test] + fn create_async_method() { + check_assist( + generate_function, + r" +//- minicore: result +struct S; +async fn foo() { + if let Err(()) = S.$0bar(42).await {} +} +", + r" +struct S; +impl S { + async fn bar(&self, arg: i32) -> Result<_, ()> { + ${0:todo!()} + } +} +async fn foo() { + if let Err(()) = S.bar(42).await {} +} +", + ) + } + + #[test] fn create_static_method() { check_assist( generate_function, @@ -2422,6 +2463,31 @@ fn foo() {S::bar();} } #[test] + fn create_async_static_method() { + check_assist( + generate_function, + r" +//- minicore: result +struct S; +async fn foo() { + if let Err(()) = S::$0bar(42).await {} +} +", + r" +struct S; +impl S { + async fn bar(arg: i32) -> Result<_, ()> { + ${0:todo!()} + } +} +async fn foo() { + if let Err(()) = S::bar(42).await {} +} +", + ) + } + + #[test] fn create_generic_static_method() { check_assist( generate_function, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs index 28d815e81b4..797180fa189 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs @@ -958,7 +958,6 @@ fn main() { ); } - // FIXME: const generics aren't being substituted, this is blocked on better support for them #[test] fn inline_substitutes_generics() { check_assist( @@ -982,7 +981,7 @@ fn foo<T, const N: usize>() { fn bar<U, const M: usize>() {} fn main() { - bar::<usize, N>(); + bar::<usize, {0}>(); } "#, ); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs new file mode 100644 index 00000000000..5b1540b50ca --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs @@ -0,0 +1,722 @@ +use syntax::{ast, AstNode}; + +use crate::{AssistContext, AssistId, AssistKind, Assists}; + +// Assist: inline_const_as_literal +// +// Evaluate and inline const variable as literal. +// +// ``` +// const STRING: &str = "Hello, World!"; +// +// fn something() -> &'static str { +// STRING$0 +// } +// ``` +// -> +// ``` +// const STRING: &str = "Hello, World!"; +// +// fn something() -> &'static str { +// "Hello, World!" +// } +// ``` +pub(crate) fn inline_const_as_literal(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let variable = ctx.find_node_at_offset::<ast::PathExpr>()?; + + if let hir::PathResolution::Def(hir::ModuleDef::Const(konst)) = + ctx.sema.resolve_path(&variable.path()?)? + { + let konst_ty = konst.ty(ctx.sema.db); + + // Used as the upper limit for recursive calls if no TCO is available + let fuel = 20; + + // There is no way to have a const static reference to a type that contains a interior + // mutability cell. + + // FIXME: Add support to handle type aliases for builtin scalar types. + validate_type_recursively(ctx, Some(&konst_ty), false, fuel)?; + + let expr = konst.value(ctx.sema.db)?; + + let value = match expr { + ast::Expr::BlockExpr(_) + | ast::Expr::Literal(_) + | ast::Expr::RefExpr(_) + | ast::Expr::ArrayExpr(_) + | ast::Expr::TupleExpr(_) + | ast::Expr::IfExpr(_) + | ast::Expr::ParenExpr(_) + | ast::Expr::MatchExpr(_) + | ast::Expr::MacroExpr(_) + | ast::Expr::BinExpr(_) + | ast::Expr::CallExpr(_) => match konst.render_eval(ctx.sema.db) { + Ok(result) => result, + Err(_) => return None, + }, + _ => return None, + }; + + let id = AssistId("inline_const_as_literal", AssistKind::RefactorInline); + + let label = format!("Inline const as literal"); + let target = variable.syntax().text_range(); + + return acc.add(id, label, target, |edit| { + edit.replace(variable.syntax().text_range(), value); + }); + } + None +} + +fn validate_type_recursively( + ctx: &AssistContext<'_>, + ty_hir: Option<&hir::Type>, + refed: bool, + fuel: i32, +) -> Option<()> { + match (fuel > 0, ty_hir) { + (true, Some(ty)) if ty.is_reference() => validate_type_recursively( + ctx, + ty.as_reference().map(|(ty, _)| ty).as_ref(), + true, + // FIXME: Saving fuel when `&` repeating might not be a good idea if there's no TCO. + if refed { fuel } else { fuel - 1 }, + ), + (true, Some(ty)) if ty.is_array() => validate_type_recursively( + ctx, + ty.as_array(ctx.db()).map(|(ty, _)| ty).as_ref(), + false, + fuel - 1, + ), + (true, Some(ty)) if ty.is_tuple() => ty + .tuple_fields(ctx.db()) + .iter() + .all(|ty| validate_type_recursively(ctx, Some(ty), false, fuel - 1).is_some()) + .then_some(()), + (true, Some(ty)) if refed && ty.is_slice() => { + validate_type_recursively(ctx, ty.as_slice().as_ref(), false, fuel - 1) + } + (_, Some(ty)) => match ty.as_builtin() { + // `const A: str` is not correct, but `const A: &builtin` is. + Some(builtin) if refed || (!refed && !builtin.is_str()) => Some(()), + _ => None, + }, + _ => None, + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::tests::{check_assist, check_assist_not_applicable}; + + const NUMBER: u8 = 1; + const BOOL: u8 = 2; + const STR: u8 = 4; + const CHAR: u8 = 8; + + const TEST_PAIRS: &[(&str, &str, u8)] = &[ + ("u8", "0", NUMBER), + ("u16", "0", NUMBER), + ("u32", "0", NUMBER), + ("u64", "0", NUMBER), + ("u128", "0", NUMBER), + ("usize", "0", NUMBER), + ("i8", "0", NUMBER), + ("i16", "0", NUMBER), + ("i32", "0", NUMBER), + ("i64", "0", NUMBER), + ("i128", "0", NUMBER), + ("isize", "0", NUMBER), + ("bool", "false", BOOL), + ("&str", "\"str\"", STR), + ("char", "'c'", CHAR), + ]; + + // -----------Not supported----------- + #[test] + fn inline_const_as_literal_const_fn_call_slice() { + TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + check_assist_not_applicable( + inline_const_as_literal, + &format!( + r#" + const fn abc() -> &[{ty}] {{ &[{val}] }} + const ABC: &[{ty}] = abc(); + fn a() {{ A$0BC }} + "# + ), + ); + }); + } + + #[test] + fn inline_const_as_literal_expr_as_str_lit_not_applicable_const() { + check_assist_not_applicable( + inline_const_as_literal, + r#" + const STR$0ING: &str = "Hello, World!"; + + fn something() -> &'static str { + STRING + } + "#, + ); + } + + #[test] + fn inline_const_as_struct_() { + check_assist_not_applicable( + inline_const_as_literal, + r#" + struct A; + const STRUKT: A = A; + + fn something() -> A { + STRU$0KT + } + "#, + ); + } + + #[test] + fn inline_const_as_enum_() { + check_assist_not_applicable( + inline_const_as_literal, + r#" + enum A { A, B, C } + const ENUM: A = A::A; + + fn something() -> A { + EN$0UM + } + "#, + ); + } + + #[test] + fn inline_const_as_tuple_closure() { + check_assist_not_applicable( + inline_const_as_literal, + r#" + const CLOSURE: (&dyn Fn(i32) -> i32) = (&|num| -> i32 { num }); + fn something() -> (&dyn Fn(i32) -> i32) { + STRU$0KT + } + "#, + ); + } + + #[test] + fn inline_const_as_closure_() { + check_assist_not_applicable( + inline_const_as_literal, + r#" + const CLOSURE: &dyn Fn(i32) -> i32 = &|num| -> i32 { num }; + fn something() -> &dyn Fn(i32) -> i32 { + STRU$0KT + } + "#, + ); + } + + #[test] + fn inline_const_as_fn_() { + check_assist_not_applicable( + inline_const_as_literal, + r#" + struct S(i32); + const CON: fn(i32) -> S = S; + fn something() { + let x = CO$0N; + } + "#, + ); + } + + // ---------------------------- + + #[test] + fn inline_const_as_literal_const_expr() { + TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + check_assist( + inline_const_as_literal, + &format!( + r#" + const ABC: {ty} = {val}; + fn a() {{ A$0BC }} + "# + ), + &format!( + r#" + const ABC: {ty} = {val}; + fn a() {{ {val} }} + "# + ), + ); + }); + } + + #[test] + fn inline_const_as_literal_const_block_expr() { + TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + check_assist( + inline_const_as_literal, + &format!( + r#" + const ABC: {ty} = {{ {val} }}; + fn a() {{ A$0BC }} + "# + ), + &format!( + r#" + const ABC: {ty} = {{ {val} }}; + fn a() {{ {val} }} + "# + ), + ); + }); + } + + #[test] + fn inline_const_as_literal_const_block_eval_expr() { + TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + check_assist( + inline_const_as_literal, + &format!( + r#" + const ABC: {ty} = {{ true; {val} }}; + fn a() {{ A$0BC }} + "# + ), + &format!( + r#" + const ABC: {ty} = {{ true; {val} }}; + fn a() {{ {val} }} + "# + ), + ); + }); + } + + #[test] + fn inline_const_as_literal_const_block_eval_block_expr() { + TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + check_assist( + inline_const_as_literal, + &format!( + r#" + const ABC: {ty} = {{ true; {{ {val} }} }}; + fn a() {{ A$0BC }} + "# + ), + &format!( + r#" + const ABC: {ty} = {{ true; {{ {val} }} }}; + fn a() {{ {val} }} + "# + ), + ); + }); + } + + #[test] + fn inline_const_as_literal_const_fn_call_block_nested_builtin() { + TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + check_assist( + inline_const_as_literal, + &format!( + r#" + const fn abc() -> {ty} {{ {{ {{ {{ {val} }} }} }} }} + const ABC: {ty} = abc(); + fn a() {{ A$0BC }} + "# + ), + &format!( + r#" + const fn abc() -> {ty} {{ {{ {{ {{ {val} }} }} }} }} + const ABC: {ty} = abc(); + fn a() {{ {val} }} + "# + ), + ); + }); + } + + #[test] + fn inline_const_as_literal_const_fn_call_tuple() { + TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + check_assist( + inline_const_as_literal, + &format!( + r#" + const fn abc() -> ({ty}, {ty}) {{ ({val}, {val}) }} + const ABC: ({ty}, {ty}) = abc(); + fn a() {{ A$0BC }} + "# + ), + &format!( + r#" + const fn abc() -> ({ty}, {ty}) {{ ({val}, {val}) }} + const ABC: ({ty}, {ty}) = abc(); + fn a() {{ ({val}, {val}) }} + "# + ), + ); + }); + } + + #[test] + fn inline_const_as_literal_const_fn_call_builtin() { + TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + check_assist( + inline_const_as_literal, + &format!( + r#" + const fn abc() -> {ty} {{ {val} }} + const ABC: {ty} = abc(); + fn a() {{ A$0BC }} + "# + ), + &format!( + r#" + const fn abc() -> {ty} {{ {val} }} + const ABC: {ty} = abc(); + fn a() {{ {val} }} + "# + ), + ); + }); + } + + #[test] + fn inline_const_as_literal_scalar_operators() { + check_assist( + inline_const_as_literal, + r#" + const ABC: i32 = 1 + 2 + 3; + fn a() { A$0BC } + "#, + r#" + const ABC: i32 = 1 + 2 + 3; + fn a() { 6 } + "#, + ); + } + #[test] + fn inline_const_as_literal_block_scalar_calculate_expr() { + check_assist( + inline_const_as_literal, + r#" + const ABC: i32 = { 1 + 2 + 3 }; + fn a() { A$0BC } + "#, + r#" + const ABC: i32 = { 1 + 2 + 3 }; + fn a() { 6 } + "#, + ); + } + + #[test] + fn inline_const_as_literal_block_scalar_calculate_param_expr() { + check_assist( + inline_const_as_literal, + r#" + const ABC: i32 = { (1 + 2 + 3) }; + fn a() { A$0BC } + "#, + r#" + const ABC: i32 = { (1 + 2 + 3) }; + fn a() { 6 } + "#, + ); + } + + #[test] + fn inline_const_as_literal_block_tuple_scalar_calculate_block_expr() { + check_assist( + inline_const_as_literal, + r#" + const ABC: (i32, i32) = { (1, { 2 + 3 }) }; + fn a() { A$0BC } + "#, + r#" + const ABC: (i32, i32) = { (1, { 2 + 3 }) }; + fn a() { (1, 5) } + "#, + ); + } + + // FIXME: Add support for nested ref slices when using `render_eval` + #[test] + fn inline_const_as_literal_block_slice() { + check_assist_not_applicable( + inline_const_as_literal, + r#" + const ABC: &[&[&[&[&[&[i32]]]]]] = { &[&[&[&[&[&[10, 20, 30]]]]]] }; + fn a() { A$0BC } + "#, + ); + } + + // FIXME: Add support for unary tuple expressions when using `render_eval`. + // `const fn abc() -> (i32) { (1) }` will results in `1` instead of `(1)` because it's evaluated + // as a paren expr. + #[test] + fn inline_const_as_literal_block_tuple() { + check_assist( + inline_const_as_literal, + r#" + const ABC: (([i32; 3]), (i32), ((&str, i32), i32), i32) = { (([1, 2, 3]), (10), (("hello", 10), 20), 30) }; + fn a() { A$0BC } + "#, + r#" + const ABC: (([i32; 3]), (i32), ((&str, i32), i32), i32) = { (([1, 2, 3]), (10), (("hello", 10), 20), 30) }; + fn a() { ([1, 2, 3], 10, (("hello", 10), 20), 30) } + "#, + ); + } + + #[test] + fn inline_const_as_literal_block_slice_single() { + check_assist( + inline_const_as_literal, + r#" + const ABC: [i32; 1] = { [10] }; + fn a() { A$0BC } + "#, + r#" + const ABC: [i32; 1] = { [10] }; + fn a() { [10] } + "#, + ); + } + + #[test] + fn inline_const_as_literal_block_array() { + check_assist( + inline_const_as_literal, + r#" + const ABC: [[[i32; 1]; 1]; 1] = { [[[10]]] }; + fn a() { A$0BC } + "#, + r#" + const ABC: [[[i32; 1]; 1]; 1] = { [[[10]]] }; + fn a() { [[[10]]] } + "#, + ); + } + + #[test] + fn inline_const_as_literal_block_recursive() { + check_assist( + inline_const_as_literal, + r#" + const ABC: &str = { { { { "hello" } } } }; + fn a() { A$0BC } + "#, + r#" + const ABC: &str = { { { { "hello" } } } }; + fn a() { "hello" } + "#, + ); + } + + #[test] + fn inline_const_as_literal_expr_as_str_lit() { + check_assist( + inline_const_as_literal, + r#" + const STRING: &str = "Hello, World!"; + + fn something() -> &'static str { + STR$0ING + } + "#, + r#" + const STRING: &str = "Hello, World!"; + + fn something() -> &'static str { + "Hello, World!" + } + "#, + ); + } + + #[test] + fn inline_const_as_literal_eval_const_block_expr_to_str_lit() { + check_assist( + inline_const_as_literal, + r#" + const STRING: &str = { + let x = 9; + if x + 10 == 21 { + "Hello, World!" + } else { + "World, Hello!" + } + }; + + fn something() -> &'static str { + STR$0ING + } + "#, + r#" + const STRING: &str = { + let x = 9; + if x + 10 == 21 { + "Hello, World!" + } else { + "World, Hello!" + } + }; + + fn something() -> &'static str { + "World, Hello!" + } + "#, + ); + } + + #[test] + fn inline_const_as_literal_eval_const_block_macro_expr_to_str_lit() { + check_assist( + inline_const_as_literal, + r#" + macro_rules! co {() => {"World, Hello!"};} + const STRING: &str = { co!() }; + + fn something() -> &'static str { + STR$0ING + } + "#, + r#" + macro_rules! co {() => {"World, Hello!"};} + const STRING: &str = { co!() }; + + fn something() -> &'static str { + "World, Hello!" + } + "#, + ); + } + + #[test] + fn inline_const_as_literal_eval_const_match_expr_to_str_lit() { + check_assist( + inline_const_as_literal, + r#" + const STRING: &str = match 9 + 10 { + 0..18 => "Hello, World!", + _ => "World, Hello!" + }; + + fn something() -> &'static str { + STR$0ING + } + "#, + r#" + const STRING: &str = match 9 + 10 { + 0..18 => "Hello, World!", + _ => "World, Hello!" + }; + + fn something() -> &'static str { + "World, Hello!" + } + "#, + ); + } + + #[test] + fn inline_const_as_literal_eval_const_if_expr_to_str_lit() { + check_assist( + inline_const_as_literal, + r#" + const STRING: &str = if 1 + 2 == 4 { + "Hello, World!" + } else { + "World, Hello!" + } + + fn something() -> &'static str { + STR$0ING + } + "#, + r#" + const STRING: &str = if 1 + 2 == 4 { + "Hello, World!" + } else { + "World, Hello!" + } + + fn something() -> &'static str { + "World, Hello!" + } + "#, + ); + } + + #[test] + fn inline_const_as_literal_eval_const_macro_expr_to_str_lit() { + check_assist( + inline_const_as_literal, + r#" + macro_rules! co {() => {"World, Hello!"};} + const STRING: &str = co!(); + + fn something() -> &'static str { + STR$0ING + } + "#, + r#" + macro_rules! co {() => {"World, Hello!"};} + const STRING: &str = co!(); + + fn something() -> &'static str { + "World, Hello!" + } + "#, + ); + } + + #[test] + fn inline_const_as_literal_eval_const_call_expr_to_str_lit() { + check_assist( + inline_const_as_literal, + r#" + const fn const_call() -> &'static str {"World, Hello!"} + const STRING: &str = const_call(); + + fn something() -> &'static str { + STR$0ING + } + "#, + r#" + const fn const_call() -> &'static str {"World, Hello!"} + const STRING: &str = const_call(); + + fn something() -> &'static str { + "World, Hello!" + } + "#, + ); + } + + #[test] + fn inline_const_as_literal_expr_as_str_lit_not_applicable() { + check_assist_not_applicable( + inline_const_as_literal, + r#" + const STRING: &str = "Hello, World!"; + + fn something() -> &'static str { + STRING $0 + } + "#, + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs index 40ee4771d17..63db6063361 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs @@ -158,9 +158,8 @@ pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< #[cfg(test)] mod tests { - use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; - use super::*; + use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; #[test] fn make_raw_string_target() { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index 36ac8c71d81..3bdd795bea8 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -1,8 +1,5 @@ use hir::{InFile, ModuleDef}; -use ide_db::{ - helpers::mod_path_to_ast, imports::import_assets::NameToImport, items_locator, - syntax_helpers::insert_whitespace_into_node::insert_ws_into, -}; +use ide_db::{helpers::mod_path_to_ast, imports::import_assets::NameToImport, items_locator}; use itertools::Itertools; use syntax::{ ast::{self, AstNode, HasName}, @@ -182,7 +179,11 @@ fn impl_def_from_trait( let impl_def = { use syntax::ast::Impl; let text = generate_trait_impl_text(adt, trait_path.to_string().as_str(), ""); - let parse = syntax::SourceFile::parse(&text); + // FIXME: `generate_trait_impl_text` currently generates two newlines + // at the front, but these leading newlines should really instead be + // inserted at the same time the impl is inserted + assert_eq!(&text[..2], "\n\n", "`generate_trait_impl_text` output changed"); + let parse = syntax::SourceFile::parse(&text[2..]); let node = match parse.tree().syntax().descendants().find_map(Impl::cast) { Some(it) => it, None => { @@ -193,24 +194,13 @@ fn impl_def_from_trait( ) } }; - let node = node.clone_subtree(); + let node = node.clone_for_update(); assert_eq!(node.syntax().text_range().start(), 0.into()); node }; - let trait_items = trait_items - .into_iter() - .map(|it| { - if sema.hir_file_for(it.syntax()).is_macro() { - if let Some(it) = ast::AssocItem::cast(insert_ws_into(it.syntax().clone())) { - return it; - } - } - it.clone_for_update() - }) - .collect(); - let (impl_def, first_assoc_item) = - add_trait_assoc_items_to_impl(sema, trait_items, trait_, impl_def, target_scope); + let first_assoc_item = + add_trait_assoc_items_to_impl(sema, &trait_items, trait_, &impl_def, target_scope); // Generate a default `impl` function body for the derived trait. if let ast::AssocItem::Fn(ref func) = first_assoc_item { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs index bd282e53434..111753bf309 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -161,6 +161,7 @@ mod handlers { mod generate_delegate_methods; mod add_return_type; mod inline_call; + mod inline_const_as_literal; mod inline_local_variable; mod inline_macro; mod inline_type_alias; @@ -265,6 +266,7 @@ mod handlers { generate_new::generate_new, inline_call::inline_call, inline_call::inline_into_callers, + inline_const_as_literal::inline_const_as_literal, inline_local_variable::inline_local_variable, inline_type_alias::inline_type_alias, inline_type_alias::inline_type_alias_uses, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index 8a35fd290e6..c097e073980 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -1480,6 +1480,27 @@ fn foo(name: Option<&str>) { } #[test] +fn doctest_inline_const_as_literal() { + check_doc_test( + "inline_const_as_literal", + r#####" +const STRING: &str = "Hello, World!"; + +fn something() -> &'static str { + STRING$0 +} +"#####, + r#####" +const STRING: &str = "Hello, World!"; + +fn something() -> &'static str { + "Hello, World!" +} +"#####, + ) +} + +#[test] fn doctest_inline_into_callers() { check_doc_test( "inline_into_callers", diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index 8f7ea26306c..03d8553506f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -3,8 +3,11 @@ use std::ops; pub(crate) use gen_trait_fn_body::gen_trait_fn_body; -use hir::{db::HirDatabase, HirDisplay, Semantics}; -use ide_db::{famous_defs::FamousDefs, path_transform::PathTransform, RootDatabase, SnippetCap}; +use hir::{db::HirDatabase, HirDisplay, InFile, Semantics}; +use ide_db::{ + famous_defs::FamousDefs, path_transform::PathTransform, + syntax_helpers::insert_whitespace_into_node::insert_ws_into, RootDatabase, SnippetCap, +}; use stdx::format_to; use syntax::{ ast::{ @@ -91,30 +94,21 @@ pub fn filter_assoc_items( sema: &Semantics<'_, RootDatabase>, items: &[hir::AssocItem], default_methods: DefaultMethods, -) -> Vec<ast::AssocItem> { - fn has_def_name(item: &ast::AssocItem) -> bool { - match item { - ast::AssocItem::Fn(def) => def.name(), - ast::AssocItem::TypeAlias(def) => def.name(), - ast::AssocItem::Const(def) => def.name(), - ast::AssocItem::MacroCall(_) => None, - } - .is_some() - } - - items +) -> Vec<InFile<ast::AssocItem>> { + return items .iter() // Note: This throws away items with no source. - .filter_map(|&i| { - let item = match i { - hir::AssocItem::Function(i) => ast::AssocItem::Fn(sema.source(i)?.value), - hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(sema.source(i)?.value), - hir::AssocItem::Const(i) => ast::AssocItem::Const(sema.source(i)?.value), + .copied() + .filter_map(|assoc_item| { + let item = match assoc_item { + hir::AssocItem::Function(it) => sema.source(it)?.map(ast::AssocItem::Fn), + hir::AssocItem::TypeAlias(it) => sema.source(it)?.map(ast::AssocItem::TypeAlias), + hir::AssocItem::Const(it) => sema.source(it)?.map(ast::AssocItem::Const), }; Some(item) }) .filter(has_def_name) - .filter(|it| match it { + .filter(|it| match &it.value { ast::AssocItem::Fn(def) => matches!( (default_methods, def.body()), (DefaultMethods::Only, Some(_)) | (DefaultMethods::No, None) @@ -125,31 +119,58 @@ pub fn filter_assoc_items( ), _ => default_methods == DefaultMethods::No, }) - .collect::<Vec<_>>() + .collect(); + + fn has_def_name(item: &InFile<ast::AssocItem>) -> bool { + match &item.value { + ast::AssocItem::Fn(def) => def.name(), + ast::AssocItem::TypeAlias(def) => def.name(), + ast::AssocItem::Const(def) => def.name(), + ast::AssocItem::MacroCall(_) => None, + } + .is_some() + } } +/// Given `original_items` retrieved from the trait definition (usually by +/// [`filter_assoc_items()`]), clones each item for update and applies path transformation to it, +/// then inserts into `impl_`. Returns the modified `impl_` and the first associated item that got +/// inserted. pub fn add_trait_assoc_items_to_impl( sema: &Semantics<'_, RootDatabase>, - items: Vec<ast::AssocItem>, + original_items: &[InFile<ast::AssocItem>], trait_: hir::Trait, - impl_: ast::Impl, + impl_: &ast::Impl, target_scope: hir::SemanticsScope<'_>, -) -> (ast::Impl, ast::AssocItem) { - let source_scope = sema.scope_for_def(trait_); - - let transform = PathTransform::trait_impl(&target_scope, &source_scope, trait_, impl_.clone()); - +) -> ast::AssocItem { let new_indent_level = IndentLevel::from_node(impl_.syntax()) + 1; - let items = items.into_iter().map(|assoc_item| { - transform.apply(assoc_item.syntax()); - assoc_item.remove_attrs_and_docs(); - assoc_item.reindent_to(new_indent_level); - assoc_item - }); + let items = original_items.into_iter().map(|InFile { file_id, value: original_item }| { + let cloned_item = { + if file_id.is_macro() { + if let Some(formatted) = + ast::AssocItem::cast(insert_ws_into(original_item.syntax().clone())) + { + return formatted; + } else { + stdx::never!("formatted `AssocItem` could not be cast back to `AssocItem`"); + } + } + original_item.clone_for_update() + }; - let res = impl_.clone_for_update(); + if let Some(source_scope) = sema.scope(original_item.syntax()) { + // FIXME: Paths in nested macros are not handled well. See + // `add_missing_impl_members::paths_in_nested_macro_should_get_transformed` test. + let transform = + PathTransform::trait_impl(&target_scope, &source_scope, trait_, impl_.clone()); + transform.apply(cloned_item.syntax()); + } + cloned_item.remove_attrs_and_docs(); + cloned_item.reindent_to(new_indent_level); + cloned_item + }); - let assoc_item_list = res.get_or_create_assoc_item_list(); + let assoc_item_list = impl_.get_or_create_assoc_item_list(); let mut first_item = None; for item in items { first_item.get_or_insert_with(|| item.clone()); @@ -172,7 +193,7 @@ pub fn add_trait_assoc_items_to_impl( assoc_item_list.add_item(item) } - (res, first_item.unwrap()) + first_item.unwrap() } #[derive(Clone, Copy, Debug)] diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs index 57a784c45b6..c5bbb7f8d75 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs @@ -105,13 +105,20 @@ fn complete_fields( mut named_field: impl FnMut(&mut Completions, hir::Field, hir::Type), mut tuple_index: impl FnMut(&mut Completions, usize, hir::Type), ) { + let mut seen_names = FxHashSet::default(); for receiver in receiver.autoderef(ctx.db) { for (field, ty) in receiver.fields(ctx.db) { - named_field(acc, field, ty); + if seen_names.insert(field.name(ctx.db)) { + named_field(acc, field, ty); + } } for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() { - // Tuple fields are always public (tuple struct fields are handled above). - tuple_index(acc, i, ty); + // Tuples are always the last type in a deref chain, so just check if the name is + // already seen without inserting into the hashset. + if !seen_names.contains(&hir::Name::new_tuple_field(i)) { + // Tuple fields are always public (tuple struct fields are handled above). + tuple_index(acc, i, ty); + } } } } @@ -672,6 +679,74 @@ impl T { } #[test] + fn test_field_no_same_name() { + check( + r#" +//- minicore: deref +struct A { field: u8 } +struct B { field: u16, another: u32 } +impl core::ops::Deref for A { + type Target = B; + fn deref(&self) -> &Self::Target { loop {} } +} +fn test(a: A) { + a.$0 +} +"#, + expect![[r#" + fd another u32 + fd field u8 + me deref() (use core::ops::Deref) fn(&self) -> &<Self as Deref>::Target + "#]], + ); + } + + #[test] + fn test_tuple_field_no_same_index() { + check( + r#" +//- minicore: deref +struct A(u8); +struct B(u16, u32); +impl core::ops::Deref for A { + type Target = B; + fn deref(&self) -> &Self::Target { loop {} } +} +fn test(a: A) { + a.$0 +} +"#, + expect![[r#" + fd 0 u8 + fd 1 u32 + me deref() (use core::ops::Deref) fn(&self) -> &<Self as Deref>::Target + "#]], + ); + } + + #[test] + fn test_tuple_struct_deref_to_tuple_no_same_index() { + check( + r#" +//- minicore: deref +struct A(u8); +impl core::ops::Deref for A { + type Target = (u16, u32); + fn deref(&self) -> &Self::Target { loop {} } +} +fn test(a: A) { + a.$0 +} +"#, + expect![[r#" + fd 0 u8 + fd 1 u32 + me deref() (use core::ops::Deref) fn(&self) -> &<Self as Deref>::Target + "#]], + ); + } + + #[test] fn test_completion_works_in_consts() { check( r#" @@ -979,4 +1054,45 @@ fn test(thing: impl Encrypt) { "#]], ) } + + #[test] + fn only_consider_same_type_once() { + check( + r#" +//- minicore: deref +struct A(u8); +struct B(u16); +impl core::ops::Deref for A { + type Target = B; + fn deref(&self) -> &Self::Target { loop {} } +} +impl core::ops::Deref for B { + type Target = A; + fn deref(&self) -> &Self::Target { loop {} } +} +fn test(a: A) { + a.$0 +} +"#, + expect![[r#" + fd 0 u8 + me deref() (use core::ops::Deref) fn(&self) -> &<Self as Deref>::Target + "#]], + ); + } + + #[test] + fn no_inference_var_in_completion() { + check( + r#" +struct S<T>(T); +fn test(s: S<Unknown>) { + s.$0 +} +"#, + expect![[r#" + fd 0 {unknown} + "#]], + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs index 7de1bf2dc13..269e40e6ef5 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -227,9 +227,8 @@ fn get_transformed_assoc_item( assoc_item: ast::AssocItem, impl_def: hir::Impl, ) -> Option<ast::AssocItem> { - let assoc_item = assoc_item.clone_for_update(); let trait_ = impl_def.trait_(ctx.db)?; - let source_scope = &ctx.sema.scope_for_def(trait_); + let source_scope = &ctx.sema.scope(assoc_item.syntax())?; let target_scope = &ctx.sema.scope(ctx.sema.source(impl_def)?.syntax().value)?; let transform = PathTransform::trait_impl( target_scope, @@ -238,6 +237,9 @@ fn get_transformed_assoc_item( ctx.sema.source(impl_def)?.value, ); + let assoc_item = assoc_item.clone_for_update(); + // FIXME: Paths in nested macros are not handled well. See + // `macro_generated_assoc_item2` test. transform.apply(assoc_item.syntax()); assoc_item.remove_attrs_and_docs(); Some(assoc_item) @@ -834,6 +836,33 @@ impl Test for () { } #[test] + fn fn_with_lifetimes() { + check_edit( + "fn foo", + r#" +trait Test<'a, 'b, T> { + fn foo(&self, a: &'a T, b: &'b T) -> &'a T; +} + +impl<'x, 'y, A> Test<'x, 'y, A> for () { + t$0 +} +"#, + r#" +trait Test<'a, 'b, T> { + fn foo(&self, a: &'a T, b: &'b T) -> &'a T; +} + +impl<'x, 'y, A> Test<'x, 'y, A> for () { + fn foo(&self, a: &'x A, b: &'y A) -> &'x A { + $0 +} +} +"#, + ); + } + + #[test] fn complete_without_name() { let test = |completion: &str, hint: &str, completed: &str, next_sibling: &str| { check_edit( @@ -1194,6 +1223,81 @@ impl Foo for Test { } #[test] + fn macro_generated_assoc_item() { + check_edit( + "fn method", + r#" +macro_rules! ty { () => { i32 } } +trait SomeTrait { type Output; } +impl SomeTrait for i32 { type Output = i64; } +macro_rules! define_method { + () => { + fn method(&mut self, params: <ty!() as SomeTrait>::Output); + }; +} +trait AnotherTrait { define_method!(); } +impl AnotherTrait for () { + $0 +} +"#, + r#" +macro_rules! ty { () => { i32 } } +trait SomeTrait { type Output; } +impl SomeTrait for i32 { type Output = i64; } +macro_rules! define_method { + () => { + fn method(&mut self, params: <ty!() as SomeTrait>::Output); + }; +} +trait AnotherTrait { define_method!(); } +impl AnotherTrait for () { + fn method(&mut self,params: <ty!()as SomeTrait>::Output) { + $0 +} +} +"#, + ); + } + + // FIXME: `T` in `ty!(T)` should be replaced by `PathTransform`. + #[test] + fn macro_generated_assoc_item2() { + check_edit( + "fn method", + r#" +macro_rules! ty { ($me:ty) => { $me } } +trait SomeTrait { type Output; } +impl SomeTrait for i32 { type Output = i64; } +macro_rules! define_method { + ($t:ty) => { + fn method(&mut self, params: <ty!($t) as SomeTrait>::Output); + }; +} +trait AnotherTrait<T: SomeTrait> { define_method!(T); } +impl AnotherTrait<i32> for () { + $0 +} +"#, + r#" +macro_rules! ty { ($me:ty) => { $me } } +trait SomeTrait { type Output; } +impl SomeTrait for i32 { type Output = i64; } +macro_rules! define_method { + ($t:ty) => { + fn method(&mut self, params: <ty!($t) as SomeTrait>::Output); + }; +} +trait AnotherTrait<T: SomeTrait> { define_method!(T); } +impl AnotherTrait<i32> for () { + fn method(&mut self,params: <ty!(T)as SomeTrait>::Output) { + $0 +} +} +"#, + ); + } + + #[test] fn includes_gat_generics() { check_edit( "type Ty", diff --git a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs index 8edda432ce3..0dd544d0ae2 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs @@ -1,7 +1,10 @@ //! Applies changes to the IDE state transactionally. use base_db::{ - salsa::{Database, Durability}, + salsa::{ + debug::{DebugQueryTable, TableEntry}, + Database, Durability, Query, QueryTable, + }, Change, SourceRootId, }; use profile::{memory_usage, Bytes}; @@ -47,16 +50,37 @@ impl RootDatabase { // | VS Code | **rust-analyzer: Memory Usage (Clears Database)** // |=== // image::https://user-images.githubusercontent.com/48062697/113065592-08559f00-91b1-11eb-8c96-64b88068ec02.gif[] - pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> { - let mut acc: Vec<(String, Bytes)> = vec![]; + pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes, usize)> { + let mut acc: Vec<(String, Bytes, usize)> = vec![]; + + fn collect_query_count<'q, Q>(table: &QueryTable<'q, Q>) -> usize + where + QueryTable<'q, Q>: DebugQueryTable, + Q: Query, + <Q as Query>::Storage: 'q, + { + struct EntryCounter(usize); + impl<K, V> FromIterator<TableEntry<K, V>> for EntryCounter { + fn from_iter<T>(iter: T) -> EntryCounter + where + T: IntoIterator<Item = TableEntry<K, V>>, + { + EntryCounter(iter.into_iter().count()) + } + } + table.entries::<EntryCounter>().0 + } + macro_rules! purge_each_query { ($($q:path)*) => {$( let before = memory_usage().allocated; - $q.in_db(self).purge(); + let table = $q.in_db(self); + let count = collect_query_count(&table); + table.purge(); let after = memory_usage().allocated; let q: $q = Default::default(); let name = format!("{:?}", q); - acc.push((name, before - after)); + acc.push((name, before - after, count)); )*} } purge_each_query![ diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs index 0ee627a44c6..73e6a920ee4 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs @@ -9,6 +9,19 @@ use syntax::{ ted, SyntaxNode, }; +#[derive(Default)] +struct AstSubsts { + types_and_consts: Vec<TypeOrConst>, + lifetimes: Vec<ast::LifetimeArg>, +} + +enum TypeOrConst { + Either(ast::TypeArg), // indistinguishable type or const param + Const(ast::ConstArg), +} + +type LifetimeName = String; + /// `PathTransform` substitutes path in SyntaxNodes in bulk. /// /// This is mostly useful for IDE code generation. If you paste some existing @@ -34,7 +47,7 @@ use syntax::{ /// ``` pub struct PathTransform<'a> { generic_def: Option<hir::GenericDef>, - substs: Vec<ast::Type>, + substs: AstSubsts, target_scope: &'a SemanticsScope<'a>, source_scope: &'a SemanticsScope<'a>, } @@ -72,7 +85,12 @@ impl<'a> PathTransform<'a> { target_scope: &'a SemanticsScope<'a>, source_scope: &'a SemanticsScope<'a>, ) -> PathTransform<'a> { - PathTransform { source_scope, target_scope, generic_def: None, substs: Vec::new() } + PathTransform { + source_scope, + target_scope, + generic_def: None, + substs: AstSubsts::default(), + } } pub fn apply(&self, syntax: &SyntaxNode) { @@ -91,12 +109,14 @@ impl<'a> PathTransform<'a> { let target_module = self.target_scope.module(); let source_module = self.source_scope.module(); let skip = match self.generic_def { - // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky + // this is a trait impl, so we need to skip the first type parameter (i.e. Self) -- this is a bit hacky Some(hir::GenericDef::Trait(_)) => 1, _ => 0, }; - let substs_by_param: FxHashMap<_, _> = self - .generic_def + let mut type_substs: FxHashMap<hir::TypeParam, ast::Type> = Default::default(); + let mut const_substs: FxHashMap<hir::ConstParam, SyntaxNode> = Default::default(); + let mut default_types: Vec<hir::TypeParam> = Default::default(); + self.generic_def .into_iter() .flat_map(|it| it.type_params(db)) .skip(skip) @@ -106,53 +126,105 @@ impl<'a> PathTransform<'a> { // can still hit those trailing values and check if they actually have // a default type. If they do, go for that type from `hir` to `ast` so // the resulting change can be applied correctly. - .zip(self.substs.iter().map(Some).chain(std::iter::repeat(None))) - .filter_map(|(k, v)| match k.split(db) { - Either::Left(_) => None, - Either::Right(t) => match v { - Some(v) => Some((k, v.clone())), - None => { - let default = t.default(db)?; - Some(( - k, - ast::make::ty( - &default - .display_source_code(db, source_module.into(), false) - .ok()?, - ), - )) + .zip(self.substs.types_and_consts.iter().map(Some).chain(std::iter::repeat(None))) + .for_each(|(k, v)| match (k.split(db), v) { + (Either::Right(k), Some(TypeOrConst::Either(v))) => { + if let Some(ty) = v.ty() { + type_substs.insert(k, ty.clone()); + } + } + (Either::Right(k), None) => { + if let Some(default) = k.default(db) { + if let Some(default) = + &default.display_source_code(db, source_module.into(), false).ok() + { + type_substs.insert(k, ast::make::ty(default).clone_for_update()); + default_types.push(k); + } + } + } + (Either::Left(k), Some(TypeOrConst::Either(v))) => { + if let Some(ty) = v.ty() { + const_substs.insert(k, ty.syntax().clone()); } - }, - }) + } + (Either::Left(k), Some(TypeOrConst::Const(v))) => { + if let Some(expr) = v.expr() { + // FIXME: expressions in curly brackets can cause ambiguity after insertion + // (e.g. `N * 2` -> `{1 + 1} * 2`; it's unclear whether `{1 + 1}` + // is a standalone statement or a part of another expresson) + // and sometimes require slight modifications; see + // https://doc.rust-lang.org/reference/statements.html#expression-statements + const_substs.insert(k, expr.syntax().clone()); + } + } + (Either::Left(_), None) => (), // FIXME: get default const value + _ => (), // ignore mismatching params + }); + let lifetime_substs: FxHashMap<_, _> = self + .generic_def + .into_iter() + .flat_map(|it| it.lifetime_params(db)) + .zip(self.substs.lifetimes.clone()) + .filter_map(|(k, v)| Some((k.name(db).display(db.upcast()).to_string(), v.lifetime()?))) .collect(); - Ctx { substs: substs_by_param, target_module, source_scope: self.source_scope } + let ctx = Ctx { + type_substs, + const_substs, + lifetime_substs, + target_module, + source_scope: self.source_scope, + }; + ctx.transform_default_type_substs(default_types); + ctx } } struct Ctx<'a> { - substs: FxHashMap<hir::TypeOrConstParam, ast::Type>, + type_substs: FxHashMap<hir::TypeParam, ast::Type>, + const_substs: FxHashMap<hir::ConstParam, SyntaxNode>, + lifetime_substs: FxHashMap<LifetimeName, ast::Lifetime>, target_module: hir::Module, source_scope: &'a SemanticsScope<'a>, } +fn postorder(item: &SyntaxNode) -> impl Iterator<Item = SyntaxNode> { + item.preorder().filter_map(|event| match event { + syntax::WalkEvent::Enter(_) => None, + syntax::WalkEvent::Leave(node) => Some(node), + }) +} + impl<'a> Ctx<'a> { fn apply(&self, item: &SyntaxNode) { // `transform_path` may update a node's parent and that would break the // tree traversal. Thus all paths in the tree are collected into a vec // so that such operation is safe. - let paths = item - .preorder() - .filter_map(|event| match event { - syntax::WalkEvent::Enter(_) => None, - syntax::WalkEvent::Leave(node) => Some(node), - }) - .filter_map(ast::Path::cast) - .collect::<Vec<_>>(); - + let paths = postorder(item).filter_map(ast::Path::cast).collect::<Vec<_>>(); for path in paths { self.transform_path(path); } + + postorder(item).filter_map(ast::Lifetime::cast).for_each(|lifetime| { + if let Some(subst) = self.lifetime_substs.get(&lifetime.syntax().text().to_string()) { + ted::replace(lifetime.syntax(), subst.clone_subtree().clone_for_update().syntax()); + } + }); } + + fn transform_default_type_substs(&self, default_types: Vec<hir::TypeParam>) { + for k in default_types { + let v = self.type_substs.get(&k).unwrap(); + // `transform_path` may update a node's parent and that would break the + // tree traversal. Thus all paths in the tree are collected into a vec + // so that such operation is safe. + let paths = postorder(&v.syntax()).filter_map(ast::Path::cast).collect::<Vec<_>>(); + for path in paths { + self.transform_path(path); + } + } + } + fn transform_path(&self, path: ast::Path) -> Option<()> { if path.qualifier().is_some() { return None; @@ -169,7 +241,7 @@ impl<'a> Ctx<'a> { match resolution { hir::PathResolution::TypeParam(tp) => { - if let Some(subst) = self.substs.get(&tp.merge()) { + if let Some(subst) = self.type_substs.get(&tp) { let parent = path.syntax().parent()?; if let Some(parent) = ast::Path::cast(parent.clone()) { // Path inside path means that there is an associated @@ -236,8 +308,12 @@ impl<'a> Ctx<'a> { } ted::replace(path.syntax(), res.syntax()) } + hir::PathResolution::ConstParam(cp) => { + if let Some(subst) = self.const_substs.get(&cp) { + ted::replace(path.syntax(), subst.clone_subtree().clone_for_update()); + } + } hir::PathResolution::Local(_) - | hir::PathResolution::ConstParam(_) | hir::PathResolution::SelfType(_) | hir::PathResolution::Def(_) | hir::PathResolution::BuiltinAttr(_) @@ -250,7 +326,7 @@ impl<'a> Ctx<'a> { // FIXME: It would probably be nicer if we could get this via HIR (i.e. get the // trait ref, and then go from the types in the substs back to the syntax). -fn get_syntactic_substs(impl_def: ast::Impl) -> Option<Vec<ast::Type>> { +fn get_syntactic_substs(impl_def: ast::Impl) -> Option<AstSubsts> { let target_trait = impl_def.trait_()?; let path_type = match target_trait { ast::Type::PathType(path) => path, @@ -261,13 +337,22 @@ fn get_syntactic_substs(impl_def: ast::Impl) -> Option<Vec<ast::Type>> { get_type_args_from_arg_list(generic_arg_list) } -fn get_type_args_from_arg_list(generic_arg_list: ast::GenericArgList) -> Option<Vec<ast::Type>> { - let mut result = Vec::new(); - for generic_arg in generic_arg_list.generic_args() { - if let ast::GenericArg::TypeArg(type_arg) = generic_arg { - result.push(type_arg.ty()?) +fn get_type_args_from_arg_list(generic_arg_list: ast::GenericArgList) -> Option<AstSubsts> { + let mut result = AstSubsts::default(); + generic_arg_list.generic_args().for_each(|generic_arg| match generic_arg { + // Const params are marked as consts on definition only, + // being passed to the trait they are indistguishable from type params; + // anyway, we don't really need to distinguish them here. + ast::GenericArg::TypeArg(type_arg) => { + result.types_and_consts.push(TypeOrConst::Either(type_arg)) } - } + // Some const values are recognized correctly. + ast::GenericArg::ConstArg(const_arg) => { + result.types_and_consts.push(TypeOrConst::Const(const_arg)); + } + ast::GenericArg::LifetimeArg(l_arg) => result.lifetimes.push(l_arg), + _ => (), + }); Some(result) } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs index 73cd5dcaf23..e8ff107bd49 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs @@ -243,6 +243,8 @@ impl Definition { DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()), DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()), DefWithBody::Variant(v) => v.source(db).map(|src| src.syntax().cloned()), + // FIXME: implement + DefWithBody::InTypeConst(_) => return SearchScope::empty(), }; return match def { Some(def) => SearchScope::file_range(def.as_ref().original_file_range_full(db)), diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt index 77714efa350..7834c66033c 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt +++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt @@ -20,8 +20,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -47,8 +49,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -74,8 +78,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -101,8 +107,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -128,8 +136,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -155,8 +165,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -182,8 +194,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt index b5adfc13d96..1a00e29384e 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt +++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt @@ -18,8 +18,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: TYPE_ALIAS, @@ -43,8 +45,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: CONST, @@ -68,8 +72,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: CONST, @@ -95,8 +101,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: ENUM, @@ -122,8 +130,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: MACRO_DEF, @@ -147,8 +157,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STATIC, @@ -174,8 +186,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -201,8 +215,12 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 2147483648, + hir_file_id: MacroFile( + MacroFile { + macro_call_id: MacroCallId( + 0, + ), + }, ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -228,8 +246,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -257,8 +277,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -286,8 +308,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -311,8 +335,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: TRAIT, @@ -338,8 +364,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: UNION, @@ -365,8 +393,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: MODULE, @@ -392,8 +422,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: MODULE, @@ -419,8 +451,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: MACRO_RULES, @@ -444,8 +478,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: FN, @@ -471,8 +507,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: MACRO_RULES, @@ -496,8 +534,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: FN, @@ -521,8 +561,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: FN, @@ -561,8 +603,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -599,8 +643,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 1, + hir_file_id: FileId( + FileId( + 1, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index a2f96977581..f75ebfa12eb 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -4423,6 +4423,29 @@ const FOO$0: Option<&i32> = Some(2).as_ref(); } #[test] +fn hover_const_eval_dyn_trait() { + check( + r#" +//- minicore: fmt, coerce_unsized, builtin_impls +use core::fmt::Debug; + +const FOO$0: &dyn Debug = &2i32; +"#, + expect![[r#" + *FOO* + + ```rust + test + ``` + + ```rust + const FOO: &dyn Debug = &2 + ``` + "#]], + ); +} + +#[test] fn hover_const_eval_slice() { check( r#" @@ -4502,6 +4525,26 @@ const FOO$0: Tree = { ``` "#]], ); + // FIXME: Show the data of unsized structs + check( + r#" +//- minicore: slice, index, coerce_unsized, transmute +#[repr(transparent)] +struct S<T: ?Sized>(T); +const FOO$0: &S<[u8]> = core::mem::transmute::<&[u8], _>(&[1, 2, 3]); +"#, + expect![[r#" + *FOO* + + ```rust + test + ``` + + ```rust + const FOO: &S<[u8]> = &S + ``` + "#]], + ); } #[test] diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs index ce1e03a069b..84eac16b9f9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs @@ -474,7 +474,7 @@ fn main() { file_id: FileId( 1, ), - range: 9332..9340, + range: 9287..9295, }, ), tooltip: "", @@ -487,7 +487,7 @@ fn main() { file_id: FileId( 1, ), - range: 9364..9368, + range: 9319..9323, }, ), tooltip: "", @@ -511,7 +511,7 @@ fn main() { file_id: FileId( 1, ), - range: 9332..9340, + range: 9287..9295, }, ), tooltip: "", @@ -524,7 +524,7 @@ fn main() { file_id: FileId( 1, ), - range: 9364..9368, + range: 9319..9323, }, ), tooltip: "", @@ -548,7 +548,7 @@ fn main() { file_id: FileId( 1, ), - range: 9332..9340, + range: 9287..9295, }, ), tooltip: "", @@ -561,7 +561,7 @@ fn main() { file_id: FileId( 1, ), - range: 9364..9368, + range: 9319..9323, }, ), tooltip: "", diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index 87e769e4230..f195f78b3ab 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -181,7 +181,7 @@ impl AnalysisHost { } /// NB: this clears the database - pub fn per_query_memory_usage(&mut self) -> Vec<(String, profile::Bytes)> { + pub fn per_query_memory_usage(&mut self) -> Vec<(String, profile::Bytes, usize)> { self.db.per_query_memory_usage() } pub fn request_cancellation(&mut self) { diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs index 8c02fe81648..dc06591ffea 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs @@ -243,6 +243,9 @@ fn traverse( let mut attr_or_derive_item = None; let mut current_macro: Option<ast::Macro> = None; let mut macro_highlighter = MacroHighlighter::default(); + + // FIXME: these are not perfectly accurate, we determine them by the real file's syntax tree + // an an attribute nested in a macro call will not emit `inside_attribute` let mut inside_attribute = false; let mut inside_macro_call = false; diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html index 327e1502d19..fa374b04f19 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html @@ -86,6 +86,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">assert</span> <span class="brace">{</span><span class="brace">}</span> <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span> <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">asm</span> <span class="brace">{</span><span class="brace">}</span> +<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span> +<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">concat</span> <span class="brace">{</span><span class="brace">}</span> <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">toho</span> <span class="brace">{</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panic<span class="punctuation">!</span><span class="parenthesis">(</span><span class="string_literal">"not yet implemented"</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span> @@ -172,4 +174,5 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="macro">toho</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">fmt"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="macro unsafe">asm</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"mov eax, </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="macro">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">concat</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="none macro">format_args</span><span class="operator macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="brace">}</span></code></pre> \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs index 887d18b989a..497992f684c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs @@ -432,6 +432,8 @@ macro_rules! panic {} macro_rules! assert {} #[rustc_builtin_macro] macro_rules! asm {} +#[rustc_builtin_macro] +macro_rules! concat {} macro_rules! toho { () => ($crate::panic!("not yet implemented")); @@ -518,6 +520,7 @@ fn main() { toho!("{}fmt", 0); asm!("mov eax, {0}"); format_args!(concat!("{}"), "{}"); + format_args!("{}", format_args!("{}", 0)); }"#, expect_file!["./test_data/highlight_strings.html"], false, diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs index 93ef4835027..96a6cdeaaff 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs @@ -153,7 +153,9 @@ fn array_or_slice_type(p: &mut Parser<'_>) { // type T = [(); 92]; T![;] => { p.bump(T![;]); + let m = p.start(); expressions::expr(p); + m.complete(p, CONST_ARG); p.expect(T![']']); ARRAY_TYPE } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0017_array_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0017_array_type.rast index 2a5c644d467..0d50144b730 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0017_array_type.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0017_array_type.rast @@ -14,8 +14,9 @@ SOURCE_FILE R_PAREN ")" SEMICOLON ";" WHITESPACE " " - LITERAL - INT_NUMBER "92" + CONST_ARG + LITERAL + INT_NUMBER "92" R_BRACK "]" SEMICOLON ";" WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_traits.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_traits.rast index 44423581e6a..3965ae9596b 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_traits.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_traits.rast @@ -51,8 +51,9 @@ SOURCE_FILE IDENT "i32" SEMICOLON ";" WHITESPACE " " - LITERAL - INT_NUMBER "1" + CONST_ARG + LITERAL + INT_NUMBER "1" R_BRACK "]" R_PAREN ")" SEMICOLON ";" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0043_complex_assignment.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0043_complex_assignment.rast index 3b02c3f96ae..f3c85b45b6b 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0043_complex_assignment.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0043_complex_assignment.rast @@ -24,8 +24,9 @@ SOURCE_FILE IDENT "u8" SEMICOLON ";" WHITESPACE " " - LITERAL - INT_NUMBER "1" + CONST_ARG + LITERAL + INT_NUMBER "1" R_BRACK "]" WHITESPACE " " R_CURLY "}" diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs index 37a45bcbb83..6fd8de59342 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs @@ -97,7 +97,7 @@ impl server::TokenStream for RustAnalyzer { match tree { bridge::TokenTree::Group(group) => { let group = Group { - delimiter: delim_to_internal(group.delimiter), + delimiter: delim_to_internal(group.delimiter, group.span), token_trees: match group.stream { Some(stream) => stream.into_iter().collect(), None => Vec::new(), @@ -221,14 +221,14 @@ impl server::TokenStream for RustAnalyzer { } } -fn delim_to_internal(d: proc_macro::Delimiter) -> tt::Delimiter { +fn delim_to_internal(d: proc_macro::Delimiter, span: bridge::DelimSpan<Span>) -> tt::Delimiter { let kind = match d { proc_macro::Delimiter::Parenthesis => tt::DelimiterKind::Parenthesis, proc_macro::Delimiter::Brace => tt::DelimiterKind::Brace, proc_macro::Delimiter::Bracket => tt::DelimiterKind::Bracket, proc_macro::Delimiter::None => tt::DelimiterKind::Invisible, }; - tt::Delimiter { open: tt::TokenId::unspecified(), close: tt::TokenId::unspecified(), kind } + tt::Delimiter { open: span.open, close: span.close, kind } } fn delim_to_external(d: tt::Delimiter) -> proc_macro::Delimiter { diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index 0aca620a675..b5fe237fc4c 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -1403,6 +1403,12 @@ fn handle_hack_cargo_workspace( .unwrap(); crate_graph.remove_and_replace(fake, original).unwrap(); } + for (_, c) in crate_graph.iter_mut() { + if c.origin.is_local() { + // LangCrateOrigin::Other is good enough for a hack. + c.origin = CrateOrigin::Lang(LangCrateOrigin::Other); + } + } sysroot .crates() .filter_map(|krate| { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml index 77f02a83101..5b72d57560b 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml @@ -68,7 +68,6 @@ ide-db.workspace = true ide-ssr.workspace = true ide.workspace = true proc-macro-api.workspace = true -proc-macro-srv-cli.workspace = true profile.workspace = true project-model.workspace = true stdx.workspace = true @@ -95,5 +94,5 @@ mbe.workspace = true [features] jemalloc = ["jemallocator", "profile/jemalloc"] force-always-assert = ["always-assert/force"] -sysroot-abi = ["proc-macro-srv-cli/sysroot-abi"] +sysroot-abi = [] in-rust-tree = ["sysroot-abi", "ide/in-rust-tree", "syntax/in-rust-tree"] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs index d5d877680a0..e3520192110 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs @@ -50,21 +50,24 @@ fn report_metric(metric: &str, value: u64, unit: &str) { } fn print_memory_usage(mut host: AnalysisHost, vfs: Vfs) { - let mut mem = host.per_query_memory_usage(); + let mem = host.per_query_memory_usage(); let before = profile::memory_usage(); drop(vfs); let vfs = before.allocated - profile::memory_usage().allocated; - mem.push(("VFS".into(), vfs)); let before = profile::memory_usage(); drop(host); - mem.push(("Unaccounted".into(), before.allocated - profile::memory_usage().allocated)); + let unaccounted = before.allocated - profile::memory_usage().allocated; + let remaining = profile::memory_usage().allocated; - mem.push(("Remaining".into(), profile::memory_usage().allocated)); - - for (name, bytes) in mem { + for (name, bytes, entries) in mem { // NOTE: Not a debug print, so avoid going through the `eprintln` defined above. - eprintln!("{bytes:>8} {name}"); + eprintln!("{bytes:>8} {entries:>6} {name}"); } + eprintln!("{vfs:>8} VFS"); + + eprintln!("{unaccounted:>8} Unaccounted"); + + eprintln!("{remaining:>8} Remaining"); } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index 2c2a9a18d2e..4cb917ce290 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -8,18 +8,20 @@ use std::{ use hir::{ db::{DefDatabase, ExpandDatabase, HirDatabase}, - AssocItem, Crate, Function, HasCrate, HasSource, HirDisplay, ModuleDef, + Adt, AssocItem, Crate, DefWithBody, HasCrate, HasSource, HirDisplay, ModuleDef, Name, }; use hir_def::{ body::{BodySourceMap, SyntheticSyntax}, hir::{ExprId, PatId}, - FunctionId, }; use hir_ty::{Interner, Substitution, TyExt, TypeFlags}; -use ide::{Analysis, AnalysisHost, LineCol, RootDatabase}; -use ide_db::base_db::{ - salsa::{self, debug::DebugQueryTable, ParallelDatabase}, - SourceDatabase, SourceDatabaseExt, +use ide::{LineCol, RootDatabase}; +use ide_db::{ + base_db::{ + salsa::{self, debug::DebugQueryTable, ParallelDatabase}, + SourceDatabase, SourceDatabaseExt, + }, + LineIndexDatabase, }; use itertools::Itertools; use oorandom::Rand32; @@ -27,7 +29,6 @@ use profile::{Bytes, StopWatch}; use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource}; use rayon::prelude::*; use rustc_hash::FxHashSet; -use stdx::format_to; use syntax::{AstNode, SyntaxNode}; use vfs::{AbsPathBuf, Vfs, VfsPath}; @@ -120,7 +121,7 @@ impl flags::AnalysisStats { eprint!(" crates: {num_crates}"); let mut num_decls = 0; - let mut funcs = Vec::new(); + let mut bodies = Vec::new(); let mut adts = Vec::new(); let mut consts = Vec::new(); while let Some(module) = visit_queue.pop() { @@ -130,40 +131,71 @@ impl flags::AnalysisStats { for decl in module.declarations(db) { num_decls += 1; match decl { - ModuleDef::Function(f) => funcs.push(f), - ModuleDef::Adt(a) => adts.push(a), - ModuleDef::Const(c) => consts.push(c), + ModuleDef::Function(f) => bodies.push(DefWithBody::from(f)), + ModuleDef::Adt(a) => { + if let Adt::Enum(e) = a { + for v in e.variants(db) { + bodies.push(DefWithBody::from(v)); + } + } + adts.push(a) + } + ModuleDef::Const(c) => { + bodies.push(DefWithBody::from(c)); + consts.push(c) + } + ModuleDef::Static(s) => bodies.push(DefWithBody::from(s)), _ => (), - } + }; } for impl_def in module.impl_defs(db) { for item in impl_def.items(db) { num_decls += 1; - if let AssocItem::Function(f) = item { - funcs.push(f); + match item { + AssocItem::Function(f) => bodies.push(DefWithBody::from(f)), + AssocItem::Const(c) => { + bodies.push(DefWithBody::from(c)); + consts.push(c); + } + _ => (), } } } } } - eprintln!(", mods: {}, decls: {num_decls}, fns: {}", visited_modules.len(), funcs.len()); + eprintln!( + ", mods: {}, decls: {num_decls}, bodies: {}, adts: {}, consts: {}", + visited_modules.len(), + bodies.len(), + adts.len(), + consts.len(), + ); eprintln!("{:<20} {}", "Item Collection:", analysis_sw.elapsed()); if self.randomize { - shuffle(&mut rng, &mut funcs); + shuffle(&mut rng, &mut bodies); + } + + if !self.skip_lowering { + self.run_body_lowering(db, &vfs, &bodies, verbosity); } if !self.skip_inference { - self.run_inference(&host, db, &vfs, &funcs, verbosity); + self.run_inference(db, &vfs, &bodies, verbosity); } if !self.skip_mir_stats { - self.run_mir_lowering(db, &funcs, verbosity); + self.run_mir_lowering(db, &bodies, verbosity); } - self.run_data_layout(db, &adts, verbosity); - self.run_const_eval(db, &consts, verbosity); + if !self.skip_data_layout { + self.run_data_layout(db, &adts, verbosity); + } + + if !self.skip_const_eval { + self.run_const_eval(db, &consts, verbosity); + } let total_span = analysis_sw.elapsed(); eprintln!("{:<20} {total_span}", "Total:"); @@ -210,8 +242,10 @@ impl flags::AnalysisStats { continue; } all += 1; - let Err(e) = db.layout_of_adt(hir_def::AdtId::from(a).into(), Substitution::empty(Interner), a.krate(db).into()) else { - continue; + let Err(e) + = db.layout_of_adt(hir_def::AdtId::from(a).into(), Substitution::empty(Interner), a.krate(db).into()) + else { + continue }; if verbosity.is_spammy() { let full_name = a @@ -227,9 +261,11 @@ impl flags::AnalysisStats { } fail += 1; } - eprintln!("{:<20} {}", "Data layouts:", sw.elapsed()); + let data_layout_time = sw.elapsed(); + eprintln!("{:<20} {}", "Data layouts:", data_layout_time); eprintln!("Failed data layouts: {fail} ({}%)", percentage(fail, all)); report_metric("failed data layouts", fail, "#"); + report_metric("data layout time", data_layout_time.time.as_millis() as u64, "ms"); } fn run_const_eval(&self, db: &RootDatabase, consts: &[hir::Const], verbosity: Verbosity) { @@ -255,61 +291,63 @@ impl flags::AnalysisStats { } fail += 1; } - eprintln!("{:<20} {}", "Const evaluation:", sw.elapsed()); + let const_eval_time = sw.elapsed(); + eprintln!("{:<20} {}", "Const evaluation:", const_eval_time); eprintln!("Failed const evals: {fail} ({}%)", percentage(fail, all)); report_metric("failed const evals", fail, "#"); + report_metric("const eval time", const_eval_time.time.as_millis() as u64, "ms"); } - fn run_mir_lowering(&self, db: &RootDatabase, funcs: &[Function], verbosity: Verbosity) { + fn run_mir_lowering(&self, db: &RootDatabase, bodies: &[DefWithBody], verbosity: Verbosity) { let mut sw = self.stop_watch(); - let all = funcs.len() as u64; + let all = bodies.len() as u64; let mut fail = 0; - for f in funcs { - let Err(e) = db.mir_body(FunctionId::from(*f).into()) else { + for &body in bodies { + let Err(e) = db.mir_body(body.into()) else { continue; }; if verbosity.is_spammy() { - let full_name = f + let full_name = body .module(db) .path_to_root(db) .into_iter() .rev() .filter_map(|it| it.name(db)) - .chain(Some(f.name(db))) + .chain(Some(body.name(db).unwrap_or_else(Name::missing))) .map(|it| it.display(db).to_string()) .join("::"); println!("Mir body for {full_name} failed due {e:?}"); } fail += 1; } - eprintln!("{:<20} {}", "MIR lowering:", sw.elapsed()); + let mir_lowering_time = sw.elapsed(); + eprintln!("{:<20} {}", "MIR lowering:", mir_lowering_time); eprintln!("Mir failed bodies: {fail} ({}%)", percentage(fail, all)); report_metric("mir failed bodies", fail, "#"); + report_metric("mir lowering time", mir_lowering_time.time.as_millis() as u64, "ms"); } fn run_inference( &self, - host: &AnalysisHost, db: &RootDatabase, vfs: &Vfs, - funcs: &[Function], + bodies: &[DefWithBody], verbosity: Verbosity, ) { let mut bar = match verbosity { Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(), _ if self.parallel || self.output.is_some() => ProgressReport::hidden(), - _ => ProgressReport::new(funcs.len() as u64), + _ => ProgressReport::new(bodies.len() as u64), }; if self.parallel { let mut inference_sw = self.stop_watch(); let snap = Snap(db.snapshot()); - funcs + bodies .par_iter() - .map_with(snap, |snap, &f| { - let f_id = FunctionId::from(f); - snap.0.body(f_id.into()); - snap.0.infer(f_id.into()); + .map_with(snap, |snap, &body| { + snap.0.body(body.into()); + snap.0.infer(body.into()); }) .count(); eprintln!("{:<20} {}", "Parallel Inference:", inference_sw.elapsed()); @@ -325,39 +363,58 @@ impl flags::AnalysisStats { let mut num_pats_unknown = 0; let mut num_pats_partially_unknown = 0; let mut num_pat_type_mismatches = 0; - let analysis = host.analysis(); - for f in funcs.iter().copied() { - let name = f.name(db); - let full_name = f - .module(db) - .path_to_root(db) - .into_iter() - .rev() - .filter_map(|it| it.name(db)) - .chain(Some(f.name(db))) - .map(|it| it.display(db).to_string()) - .join("::"); + for &body_id in bodies { + let name = body_id.name(db).unwrap_or_else(Name::missing); + let module = body_id.module(db); + let full_name = move || { + module + .krate() + .display_name(db) + .map(|it| it.canonical_name().to_string()) + .into_iter() + .chain( + module + .path_to_root(db) + .into_iter() + .filter_map(|it| it.name(db)) + .rev() + .chain(Some(body_id.name(db).unwrap_or_else(Name::missing))) + .map(|it| it.display(db).to_string()), + ) + .join("::") + }; if let Some(only_name) = self.only.as_deref() { - if name.display(db).to_string() != only_name && full_name != only_name { + if name.display(db).to_string() != only_name && full_name() != only_name { continue; } } - let mut msg = format!("processing: {full_name}"); - if verbosity.is_verbose() { - if let Some(src) = f.source(db) { - let original_file = src.file_id.original_file(db); - let path = vfs.file_path(original_file); - let syntax_range = src.value.syntax().text_range(); - format_to!(msg, " ({} {:?})", path, syntax_range); + let msg = move || { + if verbosity.is_verbose() { + let source = match body_id { + DefWithBody::Function(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::Static(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::Const(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::Variant(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::InTypeConst(_) => unimplemented!(), + }; + if let Some(src) = source { + let original_file = src.file_id.original_file(db); + let path = vfs.file_path(original_file); + let syntax_range = src.value.text_range(); + format!("processing: {} ({} {:?})", full_name(), path, syntax_range) + } else { + format!("processing: {}", full_name()) + } + } else { + format!("processing: {}", full_name()) } - } + }; if verbosity.is_spammy() { - bar.println(msg.to_string()); + bar.println(msg()); } - bar.set_message(&msg); - let f_id = FunctionId::from(f); - let (body, sm) = db.body_with_source_map(f_id.into()); - let inference_result = db.infer(f_id.into()); + bar.set_message(msg); + let (body, sm) = db.body_with_source_map(body_id.into()); + let inference_result = db.infer(body_id.into()); // region:expressions let (previous_exprs, previous_unknown, previous_partially_unknown) = @@ -368,9 +425,7 @@ impl flags::AnalysisStats { let unknown_or_partial = if ty.is_unknown() { num_exprs_unknown += 1; if verbosity.is_spammy() { - if let Some((path, start, end)) = - expr_syntax_range(db, &analysis, vfs, &sm, expr_id) - { + if let Some((path, start, end)) = expr_syntax_range(db, vfs, &sm, expr_id) { bar.println(format!( "{} {}:{}-{}:{}: Unknown type", path, @@ -394,9 +449,7 @@ impl flags::AnalysisStats { }; if self.only.is_some() && verbosity.is_spammy() { // in super-verbose mode for just one function, we print every single expression - if let Some((_, start, end)) = - expr_syntax_range(db, &analysis, vfs, &sm, expr_id) - { + if let Some((_, start, end)) = expr_syntax_range(db, vfs, &sm, expr_id) { bar.println(format!( "{}:{}-{}:{}: {}", start.line + 1, @@ -412,16 +465,14 @@ impl flags::AnalysisStats { if unknown_or_partial && self.output == Some(OutputFormat::Csv) { println!( r#"{},type,"{}""#, - location_csv_expr(db, &analysis, vfs, &sm, expr_id), + location_csv_expr(db, vfs, &sm, expr_id), ty.display(db) ); } if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) { num_expr_type_mismatches += 1; if verbosity.is_verbose() { - if let Some((path, start, end)) = - expr_syntax_range(db, &analysis, vfs, &sm, expr_id) - { + if let Some((path, start, end)) = expr_syntax_range(db, vfs, &sm, expr_id) { bar.println(format!( "{} {}:{}-{}:{}: Expected {}, got {}", path, @@ -444,7 +495,7 @@ impl flags::AnalysisStats { if self.output == Some(OutputFormat::Csv) { println!( r#"{},mismatch,"{}","{}""#, - location_csv_expr(db, &analysis, vfs, &sm, expr_id), + location_csv_expr(db, vfs, &sm, expr_id), mismatch.expected.display(db), mismatch.actual.display(db) ); @@ -454,7 +505,7 @@ impl flags::AnalysisStats { if verbosity.is_spammy() { bar.println(format!( "In {}: {} exprs, {} unknown, {} partial", - full_name, + full_name(), num_exprs - previous_exprs, num_exprs_unknown - previous_unknown, num_exprs_partially_unknown - previous_partially_unknown @@ -471,9 +522,7 @@ impl flags::AnalysisStats { let unknown_or_partial = if ty.is_unknown() { num_pats_unknown += 1; if verbosity.is_spammy() { - if let Some((path, start, end)) = - pat_syntax_range(db, &analysis, vfs, &sm, pat_id) - { + if let Some((path, start, end)) = pat_syntax_range(db, vfs, &sm, pat_id) { bar.println(format!( "{} {}:{}-{}:{}: Unknown type", path, @@ -497,8 +546,7 @@ impl flags::AnalysisStats { }; if self.only.is_some() && verbosity.is_spammy() { // in super-verbose mode for just one function, we print every single pattern - if let Some((_, start, end)) = pat_syntax_range(db, &analysis, vfs, &sm, pat_id) - { + if let Some((_, start, end)) = pat_syntax_range(db, vfs, &sm, pat_id) { bar.println(format!( "{}:{}-{}:{}: {}", start.line + 1, @@ -514,16 +562,14 @@ impl flags::AnalysisStats { if unknown_or_partial && self.output == Some(OutputFormat::Csv) { println!( r#"{},type,"{}""#, - location_csv_pat(db, &analysis, vfs, &sm, pat_id), + location_csv_pat(db, vfs, &sm, pat_id), ty.display(db) ); } if let Some(mismatch) = inference_result.type_mismatch_for_pat(pat_id) { num_pat_type_mismatches += 1; if verbosity.is_verbose() { - if let Some((path, start, end)) = - pat_syntax_range(db, &analysis, vfs, &sm, pat_id) - { + if let Some((path, start, end)) = pat_syntax_range(db, vfs, &sm, pat_id) { bar.println(format!( "{} {}:{}-{}:{}: Expected {}, got {}", path, @@ -546,7 +592,7 @@ impl flags::AnalysisStats { if self.output == Some(OutputFormat::Csv) { println!( r#"{},mismatch,"{}","{}""#, - location_csv_pat(db, &analysis, vfs, &sm, pat_id), + location_csv_pat(db, vfs, &sm, pat_id), mismatch.expected.display(db), mismatch.actual.display(db) ); @@ -556,7 +602,7 @@ impl flags::AnalysisStats { if verbosity.is_spammy() { bar.println(format!( "In {}: {} pats, {} unknown, {} partial", - full_name, + full_name(), num_pats - previous_pats, num_pats_unknown - previous_unknown, num_pats_partially_unknown - previous_partially_unknown @@ -567,6 +613,7 @@ impl flags::AnalysisStats { } bar.finish_and_clear(); + let inference_time = inference_sw.elapsed(); eprintln!( " exprs: {}, ??ty: {} ({}%), ?ty: {} ({}%), !ty: {}", num_exprs, @@ -585,12 +632,89 @@ impl flags::AnalysisStats { percentage(num_pats_partially_unknown, num_pats), num_pat_type_mismatches ); + eprintln!("{:<20} {}", "Inference:", inference_time); report_metric("unknown type", num_exprs_unknown, "#"); report_metric("type mismatches", num_expr_type_mismatches, "#"); report_metric("pattern unknown type", num_pats_unknown, "#"); report_metric("pattern type mismatches", num_pat_type_mismatches, "#"); + report_metric("inference time", inference_time.time.as_millis() as u64, "ms"); + } + + fn run_body_lowering( + &self, + db: &RootDatabase, + vfs: &Vfs, + bodies: &[DefWithBody], + verbosity: Verbosity, + ) { + let mut bar = match verbosity { + Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(), + _ if self.output.is_some() => ProgressReport::hidden(), + _ => ProgressReport::new(bodies.len() as u64), + }; - eprintln!("{:<20} {}", "Inference:", inference_sw.elapsed()); + let mut sw = self.stop_watch(); + bar.tick(); + for &body_id in bodies { + let module = body_id.module(db); + let full_name = move || { + module + .krate() + .display_name(db) + .map(|it| it.canonical_name().to_string()) + .into_iter() + .chain( + module + .path_to_root(db) + .into_iter() + .filter_map(|it| it.name(db)) + .rev() + .chain(Some(body_id.name(db).unwrap_or_else(Name::missing))) + .map(|it| it.display(db).to_string()), + ) + .join("::") + }; + if let Some(only_name) = self.only.as_deref() { + if body_id.name(db).unwrap_or_else(Name::missing).display(db).to_string() + != only_name + && full_name() != only_name + { + continue; + } + } + let msg = move || { + if verbosity.is_verbose() { + let source = match body_id { + DefWithBody::Function(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::Static(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::Const(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::Variant(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::InTypeConst(_) => unimplemented!(), + }; + if let Some(src) = source { + let original_file = src.file_id.original_file(db); + let path = vfs.file_path(original_file); + let syntax_range = src.value.text_range(); + format!("processing: {} ({} {:?})", full_name(), path, syntax_range) + } else { + format!("processing: {}", full_name()) + } + } else { + format!("processing: {}", full_name()) + } + }; + if verbosity.is_spammy() { + bar.println(msg()); + } + bar.set_message(msg); + db.body_with_source_map(body_id.into()); + bar.inc(1); + } + + bar.finish_and_clear(); + let body_lowering_time = sw.elapsed(); + eprintln!("{:<20} {}", "Body lowering:", body_lowering_time); + report_metric("body lowering time", body_lowering_time.time.as_millis() as u64, "ms"); } fn stop_watch(&self) -> StopWatch { @@ -598,13 +722,7 @@ impl flags::AnalysisStats { } } -fn location_csv_expr( - db: &RootDatabase, - analysis: &Analysis, - vfs: &Vfs, - sm: &BodySourceMap, - expr_id: ExprId, -) -> String { +fn location_csv_expr(db: &RootDatabase, vfs: &Vfs, sm: &BodySourceMap, expr_id: ExprId) -> String { let src = match sm.expr_syntax(expr_id) { Ok(s) => s, Err(SyntheticSyntax) => return "synthetic,,".to_string(), @@ -613,20 +731,14 @@ fn location_csv_expr( let node = src.map(|e| e.to_node(&root).syntax().clone()); let original_range = node.as_ref().original_file_range(db); let path = vfs.file_path(original_range.file_id); - let line_index = analysis.file_line_index(original_range.file_id).unwrap(); + let line_index = db.line_index(original_range.file_id); let text_range = original_range.range; let (start, end) = (line_index.line_col(text_range.start()), line_index.line_col(text_range.end())); format!("{path},{}:{},{}:{}", start.line + 1, start.col, end.line + 1, end.col) } -fn location_csv_pat( - db: &RootDatabase, - analysis: &Analysis, - vfs: &Vfs, - sm: &BodySourceMap, - pat_id: PatId, -) -> String { +fn location_csv_pat(db: &RootDatabase, vfs: &Vfs, sm: &BodySourceMap, pat_id: PatId) -> String { let src = match sm.pat_syntax(pat_id) { Ok(s) => s, Err(SyntheticSyntax) => return "synthetic,,".to_string(), @@ -637,7 +749,7 @@ fn location_csv_pat( }); let original_range = node.as_ref().original_file_range(db); let path = vfs.file_path(original_range.file_id); - let line_index = analysis.file_line_index(original_range.file_id).unwrap(); + let line_index = db.line_index(original_range.file_id); let text_range = original_range.range; let (start, end) = (line_index.line_col(text_range.start()), line_index.line_col(text_range.end())); @@ -646,7 +758,6 @@ fn location_csv_pat( fn expr_syntax_range( db: &RootDatabase, - analysis: &Analysis, vfs: &Vfs, sm: &BodySourceMap, expr_id: ExprId, @@ -657,7 +768,7 @@ fn expr_syntax_range( let node = src.map(|e| e.to_node(&root).syntax().clone()); let original_range = node.as_ref().original_file_range(db); let path = vfs.file_path(original_range.file_id); - let line_index = analysis.file_line_index(original_range.file_id).unwrap(); + let line_index = db.line_index(original_range.file_id); let text_range = original_range.range; let (start, end) = (line_index.line_col(text_range.start()), line_index.line_col(text_range.end())); @@ -668,7 +779,6 @@ fn expr_syntax_range( } fn pat_syntax_range( db: &RootDatabase, - analysis: &Analysis, vfs: &Vfs, sm: &BodySourceMap, pat_id: PatId, @@ -684,7 +794,7 @@ fn pat_syntax_range( }); let original_range = node.as_ref().original_file_range(db); let path = vfs.file_path(original_range.file_id); - let line_index = analysis.file_line_index(original_range.file_id).unwrap(); + let line_index = db.line_index(original_range.file_id); let text_range = original_range.range; let (start, end) = (line_index.line_col(text_range.start()), line_index.line_col(text_range.end())); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs index 4006d023def..4306d721298 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs @@ -17,9 +17,15 @@ impl flags::Diagnostics { pub fn run(self) -> anyhow::Result<()> { let mut cargo_config = CargoConfig::default(); cargo_config.sysroot = Some(RustLibSource::Discover); + let with_proc_macro_server = if let Some(p) = &self.proc_macro_srv { + let path = vfs::AbsPathBuf::assert(std::env::current_dir()?.join(&p)); + ProcMacroServerChoice::Explicit(path) + } else { + ProcMacroServerChoice::Sysroot + }; let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check: !self.disable_build_scripts, - with_proc_macro_server: ProcMacroServerChoice::Sysroot, + with_proc_macro_server, prefill_caches: false, }; let (host, _vfs, _proc_macro) = diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs index 31012c01b95..208a4e6ecd9 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs @@ -66,8 +66,6 @@ xflags::xflags! { optional --memory-usage /// Print the total length of all source and macro files (whitespace is not counted). optional --source-stats - /// Only type check, skip lowering to mir - optional --skip-mir-stats /// Only analyze items matching this path. optional -o, --only path: String @@ -80,8 +78,16 @@ xflags::xflags! { optional --disable-build-scripts /// Don't use expand proc macros. optional --disable-proc-macros - /// Only resolve names, don't run type inference. + /// Skip body lowering. + optional --skip-lowering + /// Skip type inference. optional --skip-inference + /// Skip lowering to mir + optional --skip-mir-stats + /// Skip data layout calculation + optional --skip-data-layout + /// Skip const evaluation + optional --skip-const-eval } cmd diagnostics { @@ -92,6 +98,8 @@ xflags::xflags! { optional --disable-build-scripts /// Don't use expand proc macros. optional --disable-proc-macros + /// Run a custom proc-macro-srv binary. + optional --proc-macro-srv path: PathBuf } cmd ssr { @@ -174,13 +182,16 @@ pub struct AnalysisStats { pub parallel: bool, pub memory_usage: bool, pub source_stats: bool, + pub skip_lowering: bool, + pub skip_inference: bool, pub skip_mir_stats: bool, + pub skip_data_layout: bool, + pub skip_const_eval: bool, pub only: Option<String>, pub with_deps: bool, pub no_sysroot: bool, pub disable_build_scripts: bool, pub disable_proc_macros: bool, - pub skip_inference: bool, } #[derive(Debug)] @@ -189,6 +200,7 @@ pub struct Diagnostics { pub disable_build_scripts: bool, pub disable_proc_macros: bool, + pub proc_macro_srv: Option<PathBuf>, } #[derive(Debug)] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs index d459dd115ce..c236f9c7fe1 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs @@ -4,41 +4,29 @@ use std::io::{self, Write}; /// A Simple ASCII Progress Bar -pub(crate) struct ProgressReport { +pub(crate) struct ProgressReport<'a> { curr: f32, text: String, hidden: bool, len: u64, pos: u64, - msg: String, + msg: Option<Box<dyn Fn() -> String + 'a>>, } -impl ProgressReport { - pub(crate) fn new(len: u64) -> ProgressReport { - ProgressReport { - curr: 0.0, - text: String::new(), - hidden: false, - len, - pos: 0, - msg: String::new(), - } +impl<'a> ProgressReport<'a> { + pub(crate) fn new(len: u64) -> ProgressReport<'a> { + ProgressReport { curr: 0.0, text: String::new(), hidden: false, len, pos: 0, msg: None } } - pub(crate) fn hidden() -> ProgressReport { - ProgressReport { - curr: 0.0, - text: String::new(), - hidden: true, - len: 0, - pos: 0, - msg: String::new(), - } + pub(crate) fn hidden() -> ProgressReport<'a> { + ProgressReport { curr: 0.0, text: String::new(), hidden: true, len: 0, pos: 0, msg: None } } - pub(crate) fn set_message(&mut self, msg: &str) { - self.msg = msg.to_string(); + pub(crate) fn set_message(&mut self, msg: impl Fn() -> String + 'a) { + if !self.hidden { + self.msg = Some(Box::new(msg)); + } self.tick(); } @@ -67,7 +55,12 @@ impl ProgressReport { return; } let percent = (self.curr * 100.0) as u32; - let text = format!("{}/{} {percent:3>}% {}", self.pos, self.len, self.msg); + let text = format!( + "{}/{} {percent:3>}% {}", + self.pos, + self.len, + self.msg.as_ref().map_or_else(|| String::new(), |it| it()) + ); self.update_text(&text); } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs index ebe77b8dfe7..4e57c6eb65a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs @@ -135,7 +135,7 @@ impl<'a> RequestDispatcher<'a> { R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug, R::Result: Serialize, { - self.on_with_thread_intent::<R>(ThreadIntent::Worker, f) + self.on_with_thread_intent::<true, R>(ThreadIntent::Worker, f) } /// Dispatches a latency-sensitive request onto the thread pool. @@ -148,7 +148,22 @@ impl<'a> RequestDispatcher<'a> { R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug, R::Result: Serialize, { - self.on_with_thread_intent::<R>(ThreadIntent::LatencySensitive, f) + self.on_with_thread_intent::<true, R>(ThreadIntent::LatencySensitive, f) + } + + /// Formatting requests should never block on waiting a for task thread to open up, editors will wait + /// on the response and a late formatting update might mess with the document and user. + /// We can't run this on the main thread though as we invoke rustfmt which may take arbitrary time to complete! + pub(crate) fn on_fmt_thread<R>( + &mut self, + f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>, + ) -> &mut Self + where + R: lsp_types::request::Request + 'static, + R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug, + R::Result: Serialize, + { + self.on_with_thread_intent::<false, R>(ThreadIntent::LatencySensitive, f) } pub(crate) fn finish(&mut self) { @@ -163,7 +178,7 @@ impl<'a> RequestDispatcher<'a> { } } - fn on_with_thread_intent<R>( + fn on_with_thread_intent<const MAIN_POOL: bool, R>( &mut self, intent: ThreadIntent, f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>, @@ -178,17 +193,20 @@ impl<'a> RequestDispatcher<'a> { None => return self, }; - self.global_state.task_pool.handle.spawn(intent, { - let world = self.global_state.snapshot(); - move || { - let result = panic::catch_unwind(move || { - let _pctx = stdx::panic_context::enter(panic_context); - f(world, params) - }); - match thread_result_to_response::<R>(req.id.clone(), result) { - Ok(response) => Task::Response(response), - Err(_) => Task::Retry(req), - } + let world = self.global_state.snapshot(); + if MAIN_POOL { + &mut self.global_state.task_pool.handle + } else { + &mut self.global_state.fmt_pool.handle + } + .spawn(intent, move || { + let result = panic::catch_unwind(move || { + let _pctx = stdx::panic_context::enter(panic_context); + f(world, params) + }); + match thread_result_to_response::<R>(req.id.clone(), result) { + Ok(response) => Task::Response(response), + Err(_) => Task::Retry(req), } }); @@ -289,7 +307,7 @@ pub(crate) struct NotificationDispatcher<'a> { } impl<'a> NotificationDispatcher<'a> { - pub(crate) fn on<N>( + pub(crate) fn on_sync_mut<N>( &mut self, f: fn(&mut GlobalState, N::Params) -> Result<()>, ) -> Result<&mut Self> diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs index 9f4dc444020..d5b0e3a5705 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs @@ -14,7 +14,7 @@ use nohash_hasher::IntMap; use parking_lot::{Mutex, RwLock}; use proc_macro_api::ProcMacroServer; use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts}; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; use triomphe::Arc; use vfs::AnchoredPathBuf; @@ -54,6 +54,7 @@ pub(crate) struct GlobalState { req_queue: ReqQueue, pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>, + pub(crate) fmt_pool: Handle<TaskPool<Task>, Receiver<Task>>, pub(crate) config: Arc<Config>, pub(crate) config_errors: Option<ConfigError>, @@ -111,9 +112,11 @@ pub(crate) struct GlobalState { /// the user just adds comments or whitespace to Cargo.toml, we do not want /// to invalidate any salsa caches. pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>, + pub(crate) crate_graph_file_dependencies: FxHashSet<vfs::VfsPath>, // op queues - pub(crate) fetch_workspaces_queue: OpQueue<(), Option<Vec<anyhow::Result<ProjectWorkspace>>>>, + pub(crate) fetch_workspaces_queue: + OpQueue<bool, Option<(Vec<anyhow::Result<ProjectWorkspace>>, bool)>>, pub(crate) fetch_build_data_queue: OpQueue<(), (Arc<Vec<ProjectWorkspace>>, Vec<anyhow::Result<WorkspaceBuildScripts>>)>, pub(crate) fetch_proc_macros_queue: OpQueue<Vec<ProcMacroPaths>, bool>, @@ -151,6 +154,11 @@ impl GlobalState { let handle = TaskPool::new_with_threads(sender, config.main_loop_num_threads()); Handle { handle, receiver } }; + let fmt_pool = { + let (sender, receiver) = unbounded(); + let handle = TaskPool::new_with_threads(sender, 1); + Handle { handle, receiver } + }; let mut analysis_host = AnalysisHost::new(config.lru_parse_query_capacity()); if let Some(capacities) = config.lru_query_capacities() { @@ -161,6 +169,7 @@ impl GlobalState { sender, req_queue: ReqQueue::default(), task_pool, + fmt_pool, loader, config: Arc::new(config.clone()), analysis_host, @@ -189,6 +198,7 @@ impl GlobalState { vfs_progress_n_done: 0, workspaces: Arc::new(Vec::new()), + crate_graph_file_dependencies: FxHashSet::default(), fetch_workspaces_queue: OpQueue::default(), fetch_build_data_queue: OpQueue::default(), fetch_proc_macros_queue: OpQueue::default(), @@ -202,10 +212,9 @@ impl GlobalState { pub(crate) fn process_changes(&mut self) -> bool { let _p = profile::span("GlobalState::process_changes"); - let mut workspace_structure_change = None; let mut file_changes = FxHashMap::default(); - let (change, changed_files) = { + let (change, changed_files, workspace_structure_change) = { let mut change = Change::new(); let (vfs, line_endings_map) = &mut *self.vfs.write(); let changed_files = vfs.take_changes(); @@ -260,16 +269,20 @@ impl GlobalState { .map(|(file_id, (change_kind, _))| vfs::ChangedFile { file_id, change_kind }) .collect(); + let mut workspace_structure_change = None; // A file was added or deleted let mut has_structure_changes = false; for file in &changed_files { - if let Some(path) = vfs.file_path(file.file_id).as_path() { + let vfs_path = &vfs.file_path(file.file_id); + if let Some(path) = vfs_path.as_path() { let path = path.to_path_buf(); if reload::should_refresh_for_change(&path, file.change_kind) { - workspace_structure_change = Some(path); + workspace_structure_change = Some((path.clone(), false)); } if file.is_created_or_deleted() { has_structure_changes = true; + workspace_structure_change = + Some((path, self.crate_graph_file_dependencies.contains(vfs_path))); } } @@ -294,7 +307,7 @@ impl GlobalState { let roots = self.source_root_config.partition(vfs); change.set_roots(roots); } - (change, changed_files) + (change, changed_files, workspace_structure_change) }; self.analysis_host.apply_change(change); @@ -304,9 +317,11 @@ impl GlobalState { // FIXME: ideally we should only trigger a workspace fetch for non-library changes // but something's going wrong with the source root business when we add a new local // crate see https://github.com/rust-lang/rust-analyzer/issues/13029 - if let Some(path) = workspace_structure_change { - self.fetch_workspaces_queue - .request_op(format!("workspace vfs file change: {}", path.display()), ()); + if let Some((path, force_crate_graph_reload)) = workspace_structure_change { + self.fetch_workspaces_queue.request_op( + format!("workspace vfs file change: {}", path.display()), + force_crate_graph_reload, + ); } self.proc_macro_changed = changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs index 09de6900c8f..ae1dc23153c 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs @@ -127,7 +127,7 @@ pub(crate) fn handle_did_save_text_document( if reload::should_refresh_for_change(abs_path, ChangeKind::Modify) { state .fetch_workspaces_queue - .request_op(format!("DidSaveTextDocument {}", abs_path.display()), ()); + .request_op(format!("DidSaveTextDocument {}", abs_path.display()), false); } } @@ -205,7 +205,7 @@ pub(crate) fn handle_did_change_workspace_folders( if !config.has_linked_projects() && config.detached_files().is_empty() { config.rediscover_workspaces(); - state.fetch_workspaces_queue.request_op("client workspaces changed".to_string(), ()) + state.fetch_workspaces_queue.request_op("client workspaces changed".to_string(), false) } Ok(()) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index 3f365c05942..a6a72552d57 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -18,12 +18,11 @@ use lsp_server::ErrorCode; use lsp_types::{ CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, - CodeLens, CompletionItem, DocumentFormattingParams, FoldingRange, FoldingRangeParams, - HoverContents, InlayHint, InlayHintParams, Location, LocationLink, Position, - PrepareRenameResponse, Range, RenameParams, SemanticTokensDeltaParams, - SemanticTokensFullDeltaResult, SemanticTokensParams, SemanticTokensRangeParams, - SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, SymbolTag, - TextDocumentIdentifier, Url, WorkspaceEdit, + CodeLens, CompletionItem, FoldingRange, FoldingRangeParams, HoverContents, InlayHint, + InlayHintParams, Location, LocationLink, Position, PrepareRenameResponse, Range, RenameParams, + SemanticTokensDeltaParams, SemanticTokensFullDeltaResult, SemanticTokensParams, + SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, + SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit, }; use project_model::{ManifestPath, ProjectWorkspace, TargetKind}; use serde_json::json; @@ -52,7 +51,7 @@ pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> Result< state.proc_macro_clients = Arc::from(Vec::new()); state.proc_macro_changed = false; - state.fetch_workspaces_queue.request_op("reload workspace request".to_string(), ()); + state.fetch_workspaces_queue.request_op("reload workspace request".to_string(), false); Ok(()) } @@ -115,13 +114,14 @@ pub(crate) fn handle_analyzer_status( pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> Result<String> { let _p = profile::span("handle_memory_usage"); - let mut mem = state.analysis_host.per_query_memory_usage(); - mem.push(("Remaining".into(), profile::memory_usage().allocated)); + let mem = state.analysis_host.per_query_memory_usage(); let mut out = String::new(); - for (name, bytes) in mem { - format_to!(out, "{:>8} {}\n", bytes, name); + for (name, bytes, entries) in mem { + format_to!(out, "{:>8} {:>6} {}\n", bytes, entries, name); } + format_to!(out, "{:>8} Remaining\n", profile::memory_usage().allocated); + Ok(out) } @@ -1076,7 +1076,7 @@ pub(crate) fn handle_references( pub(crate) fn handle_formatting( snap: GlobalStateSnapshot, - params: DocumentFormattingParams, + params: lsp_types::DocumentFormattingParams, ) -> Result<Option<Vec<lsp_types::TextEdit>>> { let _p = profile::span("handle_formatting"); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index 12bc638929d..02dd94e5fa5 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -11,6 +11,7 @@ use flycheck::FlycheckHandle; use ide_db::base_db::{SourceDatabaseExt, VfsPath}; use lsp_server::{Connection, Notification, Request}; use lsp_types::notification::Notification as _; +use stdx::thread::ThreadIntent; use triomphe::Arc; use vfs::FileId; @@ -115,9 +116,11 @@ impl GlobalState { self.register_did_save_capability(); } - self.fetch_workspaces_queue.request_op("startup".to_string(), ()); - if let Some((cause, ())) = self.fetch_workspaces_queue.should_start_op() { - self.fetch_workspaces(cause); + self.fetch_workspaces_queue.request_op("startup".to_string(), false); + if let Some((cause, force_crate_graph_reload)) = + self.fetch_workspaces_queue.should_start_op() + { + self.fetch_workspaces(cause, force_crate_graph_reload); } while let Some(event) = self.next_event(&inbox) { @@ -177,6 +180,9 @@ impl GlobalState { recv(self.task_pool.receiver) -> task => Some(Event::Task(task.unwrap())), + recv(self.fmt_pool.receiver) -> task => + Some(Event::Task(task.unwrap())), + recv(self.loader.receiver) -> task => Some(Event::Vfs(task.unwrap())), @@ -277,6 +283,7 @@ impl GlobalState { } } } + let event_handling_duration = loop_start.elapsed(); let state_changed = self.process_changes(); let memdocs_added_or_removed = self.mem_docs.take_changes(); @@ -364,8 +371,10 @@ impl GlobalState { } if self.config.cargo_autoreload() { - if let Some((cause, ())) = self.fetch_workspaces_queue.should_start_op() { - self.fetch_workspaces(cause); + if let Some((cause, force_crate_graph_reload)) = + self.fetch_workspaces_queue.should_start_op() + { + self.fetch_workspaces(cause, force_crate_graph_reload); } } @@ -385,9 +394,9 @@ impl GlobalState { let loop_duration = loop_start.elapsed(); if loop_duration > Duration::from_millis(100) && was_quiescent { - tracing::warn!("overly long loop turn took {loop_duration:?}: {event_dbg_msg}"); + tracing::warn!("overly long loop turn took {loop_duration:?} (event handling took {event_handling_duration:?}): {event_dbg_msg}"); self.poke_rust_analyzer_developer(format!( - "overly long loop turn took {loop_duration:?}: {event_dbg_msg}" + "overly long loop turn took {loop_duration:?} (event handling took {event_handling_duration:?}): {event_dbg_msg}" )); } Ok(()) @@ -397,7 +406,7 @@ impl GlobalState { tracing::debug!(%cause, "will prime caches"); let num_worker_threads = self.config.prime_caches_num_threads(); - self.task_pool.handle.spawn_with_sender(stdx::thread::ThreadIntent::Worker, { + self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, { let analysis = self.snapshot().analysis; move |sender| { sender.send(Task::PrimeCaches(PrimeCachesProgress::Begin)).unwrap(); @@ -468,8 +477,9 @@ impl GlobalState { let (state, msg) = match progress { ProjectWorkspaceProgress::Begin => (Progress::Begin, None), ProjectWorkspaceProgress::Report(msg) => (Progress::Report, Some(msg)), - ProjectWorkspaceProgress::End(workspaces) => { - self.fetch_workspaces_queue.op_completed(Some(workspaces)); + ProjectWorkspaceProgress::End(workspaces, force_reload_crate_graph) => { + self.fetch_workspaces_queue + .op_completed(Some((workspaces, force_reload_crate_graph))); if let Err(e) = self.fetch_workspace_error() { tracing::error!("FetchWorkspaceError:\n{e}"); } @@ -546,7 +556,6 @@ impl GlobalState { self.vfs_progress_n_total = n_total; self.vfs_progress_n_done = n_done; - // if n_total != 0 { let state = if n_done == 0 { Progress::Begin } else if n_done < n_total { @@ -562,7 +571,6 @@ impl GlobalState { Some(Progress::fraction(n_done, n_total)), None, ); - // } } } } @@ -678,6 +686,12 @@ impl GlobalState { .on_sync::<lsp_types::request::SelectionRangeRequest>(handlers::handle_selection_range) .on_sync::<lsp_ext::MatchingBrace>(handlers::handle_matching_brace) .on_sync::<lsp_ext::OnTypeFormatting>(handlers::handle_on_type_formatting) + // Formatting should be done immediately as the editor might wait on it, but we can't + // put it on the main thread as we do not want the main thread to block on rustfmt. + // So we have an extra thread just for formatting requests to make sure it gets handled + // as fast as possible. + .on_fmt_thread::<lsp_types::request::Formatting>(handlers::handle_formatting) + .on_fmt_thread::<lsp_types::request::RangeFormatting>(handlers::handle_range_formatting) // We can’t run latency-sensitive request handlers which do semantic // analysis on the main thread because that would block other // requests. Instead, we run these request handlers on higher priority @@ -695,14 +709,6 @@ impl GlobalState { .on_latency_sensitive::<lsp_types::request::SemanticTokensRangeRequest>( handlers::handle_semantic_tokens_range, ) - // Formatting is not caused by the user typing, - // but it does qualify as latency-sensitive - // because a delay before formatting is applied - // can be confusing for the user. - .on_latency_sensitive::<lsp_types::request::Formatting>(handlers::handle_formatting) - .on_latency_sensitive::<lsp_types::request::RangeFormatting>( - handlers::handle_range_formatting, - ) // All other request handlers .on::<lsp_ext::FetchDependencyList>(handlers::fetch_dependency_list) .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status) @@ -757,18 +763,28 @@ impl GlobalState { use lsp_types::notification as notifs; NotificationDispatcher { not: Some(not), global_state: self } - .on::<notifs::Cancel>(handlers::handle_cancel)? - .on::<notifs::WorkDoneProgressCancel>(handlers::handle_work_done_progress_cancel)? - .on::<notifs::DidOpenTextDocument>(handlers::handle_did_open_text_document)? - .on::<notifs::DidChangeTextDocument>(handlers::handle_did_change_text_document)? - .on::<notifs::DidCloseTextDocument>(handlers::handle_did_close_text_document)? - .on::<notifs::DidSaveTextDocument>(handlers::handle_did_save_text_document)? - .on::<notifs::DidChangeConfiguration>(handlers::handle_did_change_configuration)? - .on::<notifs::DidChangeWorkspaceFolders>(handlers::handle_did_change_workspace_folders)? - .on::<notifs::DidChangeWatchedFiles>(handlers::handle_did_change_watched_files)? - .on::<lsp_ext::CancelFlycheck>(handlers::handle_cancel_flycheck)? - .on::<lsp_ext::ClearFlycheck>(handlers::handle_clear_flycheck)? - .on::<lsp_ext::RunFlycheck>(handlers::handle_run_flycheck)? + .on_sync_mut::<notifs::Cancel>(handlers::handle_cancel)? + .on_sync_mut::<notifs::WorkDoneProgressCancel>( + handlers::handle_work_done_progress_cancel, + )? + .on_sync_mut::<notifs::DidOpenTextDocument>(handlers::handle_did_open_text_document)? + .on_sync_mut::<notifs::DidChangeTextDocument>( + handlers::handle_did_change_text_document, + )? + .on_sync_mut::<notifs::DidCloseTextDocument>(handlers::handle_did_close_text_document)? + .on_sync_mut::<notifs::DidSaveTextDocument>(handlers::handle_did_save_text_document)? + .on_sync_mut::<notifs::DidChangeConfiguration>( + handlers::handle_did_change_configuration, + )? + .on_sync_mut::<notifs::DidChangeWorkspaceFolders>( + handlers::handle_did_change_workspace_folders, + )? + .on_sync_mut::<notifs::DidChangeWatchedFiles>( + handlers::handle_did_change_watched_files, + )? + .on_sync_mut::<lsp_ext::CancelFlycheck>(handlers::handle_cancel_flycheck)? + .on_sync_mut::<lsp_ext::ClearFlycheck>(handlers::handle_clear_flycheck)? + .on_sync_mut::<lsp_ext::RunFlycheck>(handlers::handle_run_flycheck)? .finish(); Ok(()) } @@ -796,7 +812,7 @@ impl GlobalState { // Diagnostics are triggered by the user typing // so we run them on a latency sensitive thread. - self.task_pool.handle.spawn(stdx::thread::ThreadIntent::LatencySensitive, move || { + self.task_pool.handle.spawn(ThreadIntent::LatencySensitive, move || { let _p = profile::span("publish_diagnostics"); let _ctx = stdx::panic_context::enter("publish_diagnostics".to_owned()); let diagnostics = subscriptions diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index 6e8c8ea91a1..310c6b076c0 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -27,6 +27,7 @@ use ide_db::{ use itertools::Itertools; use proc_macro_api::{MacroDylib, ProcMacroServer}; use project_model::{PackageRoot, ProjectWorkspace, WorkspaceBuildScripts}; +use rustc_hash::FxHashSet; use stdx::{format_to, thread::ThreadIntent}; use syntax::SmolStr; use triomphe::Arc; @@ -46,7 +47,7 @@ use ::tt::token_id as tt; pub(crate) enum ProjectWorkspaceProgress { Begin, Report(String), - End(Vec<anyhow::Result<ProjectWorkspace>>), + End(Vec<anyhow::Result<ProjectWorkspace>>, bool), } #[derive(Debug)] @@ -85,7 +86,7 @@ impl GlobalState { ); } if self.config.linked_projects() != old_config.linked_projects() { - self.fetch_workspaces_queue.request_op("linked projects changed".to_string(), ()) + self.fetch_workspaces_queue.request_op("linked projects changed".to_string(), false) } else if self.config.flycheck() != old_config.flycheck() { self.reload_flycheck(); } @@ -110,7 +111,7 @@ impl GlobalState { if self.proc_macro_changed { status.health = lsp_ext::Health::Warning; - message.push_str("Proc-macros have changed and need to be rebuild.\n\n"); + message.push_str("Proc-macros have changed and need to be rebuilt.\n\n"); } if let Err(_) = self.fetch_build_data_error() { status.health = lsp_ext::Health::Warning; @@ -182,7 +183,7 @@ impl GlobalState { status } - pub(crate) fn fetch_workspaces(&mut self, cause: Cause) { + pub(crate) fn fetch_workspaces(&mut self, cause: Cause, force_crate_graph_reload: bool) { tracing::info!(%cause, "will fetch workspaces"); self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, { @@ -250,7 +251,10 @@ impl GlobalState { tracing::info!("did fetch workspaces {:?}", workspaces); sender - .send(Task::FetchWorkspace(ProjectWorkspaceProgress::End(workspaces))) + .send(Task::FetchWorkspace(ProjectWorkspaceProgress::End( + workspaces, + force_crate_graph_reload, + ))) .unwrap(); } }); @@ -336,15 +340,19 @@ impl GlobalState { let _p = profile::span("GlobalState::switch_workspaces"); tracing::info!(%cause, "will switch workspaces"); + let Some((workspaces, force_reload_crate_graph)) = self.fetch_workspaces_queue.last_op_result() else { return; }; + if let Err(_) = self.fetch_workspace_error() { if !self.workspaces.is_empty() { + if *force_reload_crate_graph { + self.recreate_crate_graph(cause); + } // It only makes sense to switch to a partially broken workspace // if we don't have any workspace at all yet. return; } } - let Some(workspaces) = self.fetch_workspaces_queue.last_op_result() else { return; }; let workspaces = workspaces.iter().filter_map(|res| res.as_ref().ok().cloned()).collect::<Vec<_>>(); @@ -373,6 +381,9 @@ impl GlobalState { self.workspaces = Arc::new(workspaces); } else { tracing::info!("build scripts do not match the version of the active workspace"); + if *force_reload_crate_graph { + self.recreate_crate_graph(cause); + } // Current build scripts do not match the version of the active // workspace, so there's nothing for us to update. return; @@ -467,13 +478,24 @@ impl GlobalState { }); self.source_root_config = project_folders.source_root_config; + self.recreate_crate_graph(cause); + + tracing::info!("did switch workspaces"); + } + + fn recreate_crate_graph(&mut self, cause: String) { // Create crate graph from all the workspaces - let (crate_graph, proc_macro_paths) = { + let (crate_graph, proc_macro_paths, crate_graph_file_dependencies) = { let vfs = &mut self.vfs.write().0; let loader = &mut self.loader; + // crate graph construction relies on these paths, record them so when one of them gets + // deleted or created we trigger a reconstruction of the crate graph + let mut crate_graph_file_dependencies = FxHashSet::default(); + let mut load = |path: &AbsPath| { let _p = profile::span("switch_workspaces::load"); let vfs_path = vfs::VfsPath::from(path.to_path_buf()); + crate_graph_file_dependencies.insert(vfs_path.clone()); match vfs.file_id(&vfs_path) { Some(file_id) => Some(file_id), None => { @@ -494,26 +516,25 @@ impl GlobalState { crate_graph.extend(other, &mut crate_proc_macros); proc_macros.push(crate_proc_macros); } - (crate_graph, proc_macros) + (crate_graph, proc_macros, crate_graph_file_dependencies) }; - let mut change = Change::new(); if self.config.expand_proc_macros() { self.fetch_proc_macros_queue.request_op(cause, proc_macro_paths); } + let mut change = Change::new(); change.set_crate_graph(crate_graph); self.analysis_host.apply_change(change); + self.crate_graph_file_dependencies = crate_graph_file_dependencies; self.process_changes(); self.reload_flycheck(); - - tracing::info!("did switch workspaces"); } pub(super) fn fetch_workspace_error(&self) -> Result<(), String> { let mut buf = String::new(); - let Some(last_op_result) = self.fetch_workspaces_queue.last_op_result() else { return Ok(()) }; + let Some((last_op_result, _)) = self.fetch_workspaces_queue.last_op_result() else { return Ok(()) }; if last_op_result.is_empty() { stdx::format_to!(buf, "rust-analyzer failed to discover workspace"); } else { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs index 8a9e947ded0..648bc995ad5 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs @@ -410,7 +410,7 @@ pub(crate) fn signature_help( let documentation = call_info.doc.filter(|_| config.docs).map(|doc| { lsp_types::Documentation::MarkupContent(lsp_types::MarkupContent { kind: lsp_types::MarkupKind::Markdown, - value: doc, + value: crate::markdown::format_docs(&doc), }) }); @@ -1410,7 +1410,8 @@ pub(crate) fn rename_error(err: RenameError) -> crate::LspError { #[cfg(test)] mod tests { - use ide::Analysis; + use ide::{Analysis, FilePosition}; + use test_utils::extract_offset; use triomphe::Arc; use super::*; @@ -1451,6 +1452,34 @@ fn main() { } } + #[test] + fn calling_function_with_ignored_code_in_signature() { + let text = r#" +fn foo() { + bar($0); +} +/// ``` +/// # use crate::bar; +/// bar(5); +/// ``` +fn bar(_: usize) {} +"#; + + let (offset, text) = extract_offset(text); + let (analysis, file_id) = Analysis::from_single_file(text); + let help = signature_help( + analysis.signature_help(FilePosition { file_id, offset }).unwrap().unwrap(), + CallInfoConfig { params_only: false, docs: true }, + false, + ); + let docs = match &help.signatures[help.active_signature.unwrap() as usize].documentation { + Some(lsp_types::Documentation::MarkupContent(content)) => &content.value, + _ => panic!("documentation contains markup"), + }; + assert!(docs.contains("bar(5)")); + assert!(!docs.contains("use crate::bar")); + } + // `Url` is not able to parse windows paths on unix machines. #[test] #[cfg(target_os = "windows")] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs index e130c762fc4..0bb29e7080f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs @@ -839,6 +839,17 @@ fn resolve_proc_macro() { return; } + // skip using the sysroot config as to prevent us from loading the sysroot sources + let mut rustc = std::process::Command::new(toolchain::rustc()); + rustc.args(["--print", "sysroot"]); + let output = rustc.output().unwrap(); + let sysroot = + vfs::AbsPathBuf::try_from(std::str::from_utf8(&output.stdout).unwrap().trim()).unwrap(); + + let standalone_server_name = + format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX); + let proc_macro_server_path = sysroot.join("libexec").join(&standalone_server_name); + let server = Project::with_fixture( r###" //- /foo/Cargo.toml @@ -916,7 +927,7 @@ pub fn foo(_input: TokenStream) -> TokenStream { }, "procMacro": { "enable": true, - "server": PathBuf::from(env!("CARGO_BIN_EXE_rust-analyzer")), + "server": proc_macro_server_path.as_path().as_ref(), } })) .root("foo") diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram index 4c9027dec68..b096c997448 100644 --- a/src/tools/rust-analyzer/crates/syntax/rust.ungram +++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram @@ -565,7 +565,7 @@ RefType = '&' Lifetime? 'mut'? Type ArrayType = - '[' Type ';' Expr ']' + '[' Type ';' ConstArg ']' SliceType = '[' Type ']' diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs index 61f6a04c98d..e520801ea2e 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs @@ -1207,7 +1207,7 @@ impl ArrayType { pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) } pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } - pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + pub fn const_arg(&self) -> Option<ConstArg> { support::child(&self.syntax) } pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index a07561e79a2..3c2b7e56b06 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -166,7 +166,7 @@ pub fn ty_alias( assignment: Option<(ast::Type, Option<ast::WhereClause>)>, ) -> ast::TypeAlias { let mut s = String::new(); - s.push_str(&format!("type {} ", ident)); + s.push_str(&format!("type {}", ident)); if let Some(list) = generic_param_list { s.push_str(&list.to_string()); @@ -182,9 +182,9 @@ pub fn ty_alias( if let Some(exp) = assignment { if let Some(cl) = exp.1 { - s.push_str(&format!("= {} {}", &exp.0.to_string(), &cl.to_string())); + s.push_str(&format!(" = {} {}", &exp.0.to_string(), &cl.to_string())); } else { - s.push_str(&format!("= {}", &exp.0.to_string())); + s.push_str(&format!(" = {}", &exp.0.to_string())); } } diff --git a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs index 05f32f8e51e..602baed3707 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs @@ -387,6 +387,10 @@ impl MiniCore { } } + if !active_regions.is_empty() { + panic!("unclosed regions: {:?} Add an `endregion` comment", active_regions); + } + for flag in &self.valid_flags { if !seen_regions.iter().any(|it| it == flag) { panic!("unused minicore flag: {flag:?}"); diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index c79b4e966d6..266bc2391f1 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -32,6 +32,7 @@ //! include: //! index: sized //! infallible: +//! int_impl: size_of, transmute //! iterator: option //! iterators: iterator, fn //! manually_drop: drop @@ -41,9 +42,11 @@ //! panic: fmt //! phantom_data: //! pin: +//! pointee: //! range: //! result: //! send: sized +//! size_of: sized //! sized: //! slice: //! sync: sized @@ -345,6 +348,12 @@ pub mod mem { pub fn transmute<Src, Dst>(src: Src) -> Dst; } // endregion:transmute + + // region:size_of + extern "rust-intrinsic" { + pub fn size_of<T>() -> usize; + } + // endregion:size_of } pub mod ptr { @@ -360,6 +369,14 @@ pub mod ptr { *dst = src; } // endregion:drop + + // region:pointee + #[lang = "pointee_trait"] + pub trait Pointee { + #[lang = "metadata_type"] + type Metadata; + } + // endregion:pointee } pub mod ops { @@ -859,29 +876,26 @@ pub mod fmt { } #[lang = "format_argument"] - pub struct ArgumentV1<'a> { + pub struct Argument<'a> { value: &'a Opaque, formatter: fn(&Opaque, &mut Formatter<'_>) -> Result, } - impl<'a> ArgumentV1<'a> { - pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> ArgumentV1<'b> { + impl<'a> Argument<'a> { + pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'b> { use crate::mem::transmute; - unsafe { ArgumentV1 { formatter: transmute(f), value: transmute(x) } } + unsafe { Argument { formatter: transmute(f), value: transmute(x) } } } } #[lang = "format_arguments"] pub struct Arguments<'a> { pieces: &'a [&'static str], - args: &'a [ArgumentV1<'a>], + args: &'a [Argument<'a>], } impl<'a> Arguments<'a> { - pub const fn new_v1( - pieces: &'a [&'static str], - args: &'a [ArgumentV1<'a>], - ) -> Arguments<'a> { + pub const fn new_v1(pieces: &'a [&'static str], args: &'a [Argument<'a>]) -> Arguments<'a> { Arguments { pieces, args } } } @@ -1307,6 +1321,25 @@ impl bool { } // endregion:bool_impl +// region:int_impl +macro_rules! impl_int { + ($($t:ty)*) => { + $( + impl $t { + pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self { + unsafe { mem::transmute(bytes) } + } + } + )* + } +} + +impl_int! { + usize u8 u16 u32 u64 u128 + isize i8 i16 i32 i64 i128 +} +// endregion:int_impl + // region:error pub mod error { #[rustc_has_incoherent_inherent_impls] diff --git a/src/tools/rust-analyzer/docs/user/manual.adoc b/src/tools/rust-analyzer/docs/user/manual.adoc index 5b9db10b093..b5c095fd9d8 100644 --- a/src/tools/rust-analyzer/docs/user/manual.adoc +++ b/src/tools/rust-analyzer/docs/user/manual.adoc @@ -244,7 +244,7 @@ Any other tools or libraries you will need to acquire from Flatpak. Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>. -To use `rust-analyzer`, you need to install and enable one of the two popular two popular LSP client implementations for Emacs, https://github.com/joaotavora/eglot[Eglot] or https://github.com/emacs-lsp/lsp-mode[LSP Mode]. Both enable `rust-analyzer` by default in rust buffers if it is available. +To use `rust-analyzer`, you need to install and enable one of the two popular LSP client implementations for Emacs, https://github.com/joaotavora/eglot[Eglot] or https://github.com/emacs-lsp/lsp-mode[LSP Mode]. Both enable `rust-analyzer` by default in rust buffers if it is available. ==== Eglot @@ -653,9 +653,28 @@ However, if you use some other build system, you'll have to describe the structu [source,TypeScript] ---- interface JsonProject { + /// Path to the sysroot directory. + /// + /// The sysroot is where rustc looks for the + /// crates that are built-in to rust, such as + /// std. + /// + /// https://doc.rust-lang.org/rustc/command-line-arguments.html#--sysroot-override-the-system-root + /// + /// To see the current value of sysroot, you + /// can query rustc: + /// + /// ``` + /// $ rustc --print sysroot + /// /Users/yourname/.rustup/toolchains/stable-x86_64-apple-darwin + /// ``` + sysroot?: string; /// Path to the directory with *source code* of /// sysroot crates. /// + /// By default, this is `lib/rustlib/src/rust/library` + /// relative to the sysroot. + /// /// It should point to the directory where std, /// core, and friends can be found: /// diff --git a/src/tools/rust-analyzer/editors/code/.vscodeignore b/src/tools/rust-analyzer/editors/code/.vscodeignore index 09dc27056b3..6e118f0b3ae 100644 --- a/src/tools/rust-analyzer/editors/code/.vscodeignore +++ b/src/tools/rust-analyzer/editors/code/.vscodeignore @@ -10,5 +10,6 @@ !package-lock.json !package.json !ra_syntax_tree.tmGrammar.json +!rustdoc.markdown.injection.tmGrammar.json !server !README.md diff --git a/src/tools/rust-analyzer/lib/la-arena/src/lib.rs b/src/tools/rust-analyzer/lib/la-arena/src/lib.rs index 5107f294394..f39c3a3e4ca 100644 --- a/src/tools/rust-analyzer/lib/la-arena/src/lib.rs +++ b/src/tools/rust-analyzer/lib/la-arena/src/lib.rs @@ -451,6 +451,12 @@ impl<T> Arena<T> { } } +impl<T> AsMut<[T]> for Arena<T> { + fn as_mut(&mut self) -> &mut [T] { + self.data.as_mut() + } +} + impl<T> Default for Arena<T> { fn default() -> Arena<T> { Arena { data: Vec::new() } diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs index dc902f8cb02..0ddd2c66cf9 100644 --- a/src/tools/rustdoc-gui-test/src/main.rs +++ b/src/tools/rustdoc-gui-test/src/main.rs @@ -67,7 +67,7 @@ fn find_librs<P: AsRef<Path>>(path: P) -> Option<PathBuf> { None } -fn main() { +fn main() -> Result<(), ()> { let config = Arc::new(Config::from_args(env::args().collect())); // The goal here is to check if the necessary packages are installed, and if not, we @@ -128,7 +128,10 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse } } - try_run(&mut cargo, config.verbose); + if try_run(&mut cargo, config.verbose).is_err() { + eprintln!("failed to document `{}`", entry.path().display()); + panic!("Cannot run rustdoc-gui tests"); + } } } @@ -158,5 +161,5 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse command.args(&config.test_args); - try_run(&mut command, config.verbose); + try_run(&mut command, config.verbose) } diff --git a/src/tools/rustfmt/.editorconfig b/src/tools/rustfmt/.editorconfig index 5bb92df3e04..ed6894e5c27 100644 --- a/src/tools/rustfmt/.editorconfig +++ b/src/tools/rustfmt/.editorconfig @@ -21,6 +21,3 @@ indent_size = unset indent_style = unset trim_trailing_whitespace = unset insert_final_newline = unset - -[appveyor.yml] -end_of_line = unset diff --git a/src/tools/rustfmt/.github/workflows/upload-assets.yml b/src/tools/rustfmt/.github/workflows/upload-assets.yml index 25699234a1e..7dfaa4b9204 100644 --- a/src/tools/rustfmt/.github/workflows/upload-assets.yml +++ b/src/tools/rustfmt/.github/workflows/upload-assets.yml @@ -46,10 +46,7 @@ jobs: shell: bash - name: Build release binaries - uses: actions-rs/cargo@v1 - with: - command: build - args: --release + run: cargo build --release - name: Build archive shell: bash diff --git a/src/tools/rustfmt/.travis.yml b/src/tools/rustfmt/.travis.yml deleted file mode 100644 index d699bd842ee..00000000000 --- a/src/tools/rustfmt/.travis.yml +++ /dev/null @@ -1,77 +0,0 @@ -sudo: false -language: rust -rust: nightly -os: linux -cache: - directories: - - $HOME/.cargo - -addons: - apt: - packages: - - libcurl4-openssl-dev - - libelf-dev - - libdw-dev - -matrix: - include: - - env: DEPLOY=LINUX - - env: CFG_RELEASE_CHANNEL=beta - - os: osx - - env: INTEGRATION=bitflags - - env: INTEGRATION=chalk - - env: INTEGRATION=crater - - env: INTEGRATION=error-chain - - env: INTEGRATION=glob - - env: INTEGRATION=log - - env: INTEGRATION=mdbook - - env: INTEGRATION=packed_simd - - env: INTEGRATION=rust-semverver - - env: INTEGRATION=stdsimd TARGET=x86_64-unknown-linux-gnu - - env: INTEGRATION=tempdir - - env: INTEGRATION=futures-rs - allow_failures: - # Using old configuration option - - env: INTEGRATION=rand - # Doesn't build - keep this in allow_failures as it's fragile to breaking changes of rustc. - - env: INTEGRATION=rust-clippy - # Doesn't build - seems to be because of an option - - env: INTEGRATION=packed_simd - # Doesn't build - a temporal build failure due to breaking changes in the nightly compilre - - env: INTEGRATION=rust-semverver - # can be moved back to include section after https://github.com/rust-lang-nursery/failure/pull/298 is merged - - env: INTEGRATION=failure - # `cargo test` doesn't finish - disabling for now. - # - env: INTEGRATION=cargo - -script: - - | - if [ -z ${INTEGRATION} ]; then - export CFG_RELEASE_CHANNEL=nightly - export CFG_RELEASE=nightly - cargo build - cargo test - cargo test -- --ignored - else - ./ci/integration.sh - fi - -after_success: -- if [ -z ${INTEGRATION} ]; then travis-cargo coveralls --no-sudo; fi - -before_deploy: - # TODO: cross build - - cargo build --release --target=x86_64-unknown-linux-gnu - - tar czf rustfmt-x86_64-unknown-linux-gnu.tar.gz Contributing.md Design.md README.md -C target/x86_64-unknown-linux-gnu/release/rustfmt rustfmt - -deploy: - provider: releases - api_key: - secure: "your own encrypted key" - file: - - rustfmt-x86_64-unknown-linux-gnu.tar.gz - on: - repo: nrc/rustfmt - tags: true - condition: "$DEPLOY = LINUX" - skip_cleanup: true diff --git a/src/tools/rustfmt/CHANGELOG.md b/src/tools/rustfmt/CHANGELOG.md index 60f961fa12a..0d4e057223d 100644 --- a/src/tools/rustfmt/CHANGELOG.md +++ b/src/tools/rustfmt/CHANGELOG.md @@ -2,6 +2,47 @@ ## [Unreleased] +## [1.5.3] 2023-06-20 + +### Fixed + +- When formatting doc comments with `wrap_comments = true` rustfmt will no longer wrap markdown tables [#4210](https://github.com/rust-lang/rustfmt/issues/4210) +- Properly handle wrapping comments that include a numbered list in markdown [#5416](https://github.com/rust-lang/rustfmt/issues/5416) +- Properly handle markdown sublists that utilize a `+` [#4041](https://github.com/rust-lang/rustfmt/issues/4210) +- rustfmt will no longer use shorthand initialization when rewriting a tuple struct even when `use_field_init_shorthand = true` as this leads to code that could no longer compile. + Take the following struct as an example `struct MyStruct(u64);`. rustfmt will no longer format `MyStruct { 0: 0 }` as `MyStruct { 0 }` [#5488](https://github.com/rust-lang/rustfmt/issues/5488) +- rustfmt no longer panics when formatting an empty code block in a doc comment with `format_code_in_doc_comments = true` [#5234](https://github.com/rust-lang/rustfmt/issues/5234). For example: + ```rust + /// ``` + /// + /// ``` + fn main() {} + ``` +- rustfmt no longer incorrectly duplicates the where clause bounds when using const expression in where clause bounds with feature `#![feature(generic_const_exprs)]` [#5691](https://github.com/rust-lang/rustfmt/issues/5691). e.g.: + ```rust + struct S<const C: usize> + where + [(); { num_slots!(C) }]:, { + // code ... + } + ``` +- Prevent ICE when parsing invalid attributes in `cfg_if!` macros [#5728](https://github.com/rust-lang/rustfmt/issues/5728), [#5729](https://github.com/rust-lang/rustfmt/issues/5729) +- rustfmt no longer loses comments placed between a doc comment and generic params [#5320](https://github.com/rust-lang/rustfmt/issues/5320) +- Handle explicit discriminants in enums with comments present [#5686](https://github.com/rust-lang/rustfmt/issues/5686) + +### Changed + +- Users can now control whether rustc parser errors are displayed with color using rustfmt's `--color` option. To disable colored errors pass `--color=Never` to rustfmt [#5717](https://github.com/rust-lang/rustfmt/issues/5717) + + +### Added + +- rustfmt now recognises `+` as the start of a markdown list, and won't incorrectly wrap sublists that begin with `+` when formatting doc comments with `wrap_comments = true` [#5560](https://github.com/rust-lang/rustfmt/pull/5560) + +### Misc + +- Update various dependencies, including `syn`, `cargo_metadata`, `env_logger`, and `toml` + ## [1.5.2] 2023-01-24 ### Fixed @@ -56,6 +97,8 @@ - Simplify the rustfmt help text by eliding the full path to the rustfmt binary path from the usage string when running `rustfmt --help` [#5214](https://github.com/rust-lang/rustfmt/issues/5214) +- Bumped the version for serveral dependencies. Most notably `dirs` `v2.0.1` -> `v4.0.0`. This changed the global user config directory on macOS from `$HOME/Library/Preferences` to `$HOME/Library/Application Support` [#5237](https://github.com/rust-lang/rustfmt/pull/5237) + ### Fixed - Remove duplicate imports when `imports_granularity` is set to `Item` [#4725](https://github.com/rust-lang/rustfmt/issues/4725) diff --git a/src/tools/rustfmt/Cargo.lock b/src/tools/rustfmt/Cargo.lock index 24166d51c51..999125118f8 100644 --- a/src/tools/rustfmt/Cargo.lock +++ b/src/tools/rustfmt/Cargo.lock @@ -22,23 +22,52 @@ dependencies = [ ] [[package]] -name = "anyhow" -version = "1.0.56" +name = "anstream" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" +checksum = "342258dd14006105c2b75ab1bd7543a03bdf0cfc94383303ac212a04939dff6f" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-wincon", + "concolor-override", + "concolor-query", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2" [[package]] -name = "atty" -version = "0.2.14" +name = "anstyle-parse" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +checksum = "a7d1bb534e9efed14f3e5f44e7dd1a4f709384023a4165199a4241e18dff0116" dependencies = [ - "hermit-abi", - "libc", - "winapi", + "utf8parse", +] + +[[package]] +name = "anstyle-wincon" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3127af6145b149f3287bb9a0d10ad9c5692dba8c53ad48285e5bec4063834fa" +dependencies = [ + "anstyle", + "windows-sys 0.45.0", ] [[package]] +name = "anyhow" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" + +[[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -88,18 +117,25 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.14.2" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" dependencies = [ "camino", "cargo-platform", "semver", "serde", "serde_json", + "thiserror", ] [[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -107,53 +143,69 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "3.1.8" +version = "4.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c" +checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3" dependencies = [ - "atty", - "bitflags", + "clap_builder", "clap_derive", - "indexmap", - "lazy_static", - "os_str_bytes", + "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f" +dependencies = [ + "anstream", + "anstyle", + "bitflags", + "clap_lex", "strsim", - "termcolor", - "textwrap", ] [[package]] name = "clap_derive" -version = "3.1.7" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3aab4734e083b809aaf5794e14e756d1c798d2c69c7f7de7a09a2f5214993c1" +checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", "syn", ] [[package]] -name = "crossbeam-utils" -version = "0.8.8" +name = "clap_lex" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" + +[[package]] +name = "concolor-override" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a855d4a1978dc52fb0536a04d384c2c0c1aa273597f08b77c8c4d3b2eec6037f" + +[[package]] +name = "concolor-query" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d11d52c3d7ca2e6d0040212be9e4dbbcd78b6447f535b6b561f449427944cf" dependencies = [ - "cfg-if", - "lazy_static", + "windows-sys 0.45.0", ] [[package]] -name = "derive-new" -version = "0.5.9" +name = "crossbeam-utils" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" dependencies = [ - "proc-macro2", - "quote", - "syn", + "cfg-if", + "lazy_static", ] [[package]] @@ -211,18 +263,39 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "env_logger" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" dependencies = [ - "atty", "humantime", + "is-terminal", "log", "regex", "termcolor", ] [[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -263,9 +336,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heck" @@ -275,12 +348,9 @@ checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" [[package]] name = "hermit-abi" -version = "0.1.19" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" [[package]] name = "humantime" @@ -308,15 +378,38 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.1" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown", ] [[package]] +name = "io-lifetimes" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +dependencies = [ + "hermit-abi", + "io-lifetimes", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] name = "itertools" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -339,9 +432,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.122" +version = "0.2.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259" +checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" [[package]] name = "libm" @@ -350,6 +443,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" [[package]] +name = "linux-raw-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" + +[[package]] name = "log" version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -366,18 +465,9 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "once_cell" -version = "1.10.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" - -[[package]] -name = "os_str_bytes" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" -dependencies = [ - "memchr", -] +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "packed_simd_2" @@ -390,43 +480,19 @@ dependencies = [ ] [[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] name = "proc-macro2" -version = "1.0.37" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.17" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] @@ -469,12 +535,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] -name = "rustc-workspace-hack" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" - -[[package]] name = "rustfmt-config_proc_macro" version = "0.3.0" dependencies = [ @@ -485,14 +545,13 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.5.2" +version = "1.5.3" dependencies = [ "annotate-snippets", "anyhow", "bytecount", "cargo_metadata", "clap", - "derive-new", "diff", "dirs", "env_logger", @@ -502,7 +561,6 @@ dependencies = [ "lazy_static", "log", "regex", - "rustc-workspace-hack", "rustfmt-config_proc_macro", "serde", "serde_json", @@ -515,6 +573,20 @@ dependencies = [ ] [[package]] +name = "rustix" +version = "0.37.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + +[[package]] name = "rustversion" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -546,18 +618,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.136" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", @@ -576,6 +648,15 @@ dependencies = [ ] [[package]] +name = "serde_spanned" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" +dependencies = [ + "serde", +] + +[[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -583,13 +664,13 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.91" +version = "2.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" +checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -613,25 +694,19 @@ dependencies = [ ] [[package]] -name = "textwrap" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" - -[[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", @@ -649,14 +724,45 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.8" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" dependencies = [ + "indexmap", "serde", + "serde_spanned", + "toml_datetime", + "winnow", ] [[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] name = "unicode-segmentation" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -669,22 +775,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - -[[package]] name = "unicode_categories" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" [[package]] -name = "version_check" -version = "0.9.4" +name = "utf8parse" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "walkdir" @@ -735,6 +835,147 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "winnow" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +dependencies = [ + "memchr", +] + +[[package]] name = "yansi-term" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/src/tools/rustfmt/Cargo.toml b/src/tools/rustfmt/Cargo.toml index 87ce59d0217..a8928bfcd50 100644 --- a/src/tools/rustfmt/Cargo.toml +++ b/src/tools/rustfmt/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustfmt-nightly" -version = "1.5.2" +version = "1.5.3" description = "Tool to find and fix Rust formatting issues" repository = "https://github.com/rust-lang/rustfmt" readme = "README.md" @@ -36,34 +36,28 @@ generic-simd = ["bytecount/generic-simd"] annotate-snippets = { version = "0.9", features = ["color"] } anyhow = "1.0" bytecount = "0.6" -cargo_metadata = "0.14" -clap = { version = "3.1", features = ["derive"] } -derive-new = "0.5" +cargo_metadata = "0.15.4" +clap = { version = "4.2.1", features = ["derive"] } diff = "0.1" dirs = "4.0" -env_logger = "0.9" +env_logger = "0.10.0" getopts = "0.2" ignore = "0.4" itertools = "0.10" lazy_static = "1.4" log = "0.4" regex = "1.5" -serde = { version = "1.0", features = ["derive"] } +serde = { version = "1.0.160", features = ["derive"] } serde_json = "1.0" term = "0.7" -thiserror = "1.0" -toml = "0.5" +thiserror = "1.0.40" +toml = "0.7.4" unicode-segmentation = "1.9" unicode-width = "0.1" unicode_categories = "0.1" rustfmt-config_proc_macro = { version = "0.3", path = "config_proc_macro" } -# A noop dependency that changes in the Rust repository, it's a bit of a hack. -# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` -# for more information. -rustc-workspace-hack = "1.0.0" - # Rustc dependencies are loaded from the sysroot, Cargo doesn't know about them. [package.metadata.rust-analyzer] diff --git a/src/tools/rustfmt/Configurations.md b/src/tools/rustfmt/Configurations.md index 49e7e4e6489..ac638ff91e6 100644 --- a/src/tools/rustfmt/Configurations.md +++ b/src/tools/rustfmt/Configurations.md @@ -2997,6 +2997,10 @@ See also [`brace_style`](#brace_style), [`control_brace_style`](#control_brace_s Break comments to fit on the line +Note that no wrapping will happen if: +1. The comment is the start of a markdown header doc comment +2. An URL was found in the comment + - **Default value**: `false` - **Possible values**: `true`, `false` - **Stable**: No (tracking issue: [#3347](https://github.com/rust-lang/rustfmt/issues/3347)) @@ -3011,6 +3015,11 @@ Break comments to fit on the line // commodo consequat. // Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + +// Information on the lorem ipsum can be found at the following url: https://en.wikipedia.org/wiki/Lorem_ipsum. Its text is: lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + +/// # This doc comment is a very long header (it starts with a '#'). Had it not been a header it would have been wrapped. But because it is a header, it will not be. That is because wrapping a markdown header breaks it. +struct Foo {} ``` #### `true`: @@ -3021,6 +3030,17 @@ Break comments to fit on the line // magna aliqua. Ut enim ad minim veniam, quis nostrud // exercitation ullamco laboris nisi ut aliquip ex ea // commodo consequat. + +// Lorem ipsum dolor sit amet, consectetur adipiscing elit, +// sed do eiusmod tempor incididunt ut labore et dolore +// magna aliqua. Ut enim ad minim veniam, quis nostrud +// exercitation ullamco laboris nisi ut aliquip ex ea +// commodo consequat. + +// Information on the lorem ipsum can be found at the following url: https://en.wikipedia.org/wiki/Lorem_ipsum. Its text is: lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + +/// # This doc comment is a very long header (it starts with a '#'). Had it not been a header it would have been wrapped. But because it is a header, it will not be. That is because wrapping a markdown header breaks it. +struct Foo {} ``` # Internal Options diff --git a/src/tools/rustfmt/Contributing.md b/src/tools/rustfmt/Contributing.md index 3073996019e..b986a887c92 100644 --- a/src/tools/rustfmt/Contributing.md +++ b/src/tools/rustfmt/Contributing.md @@ -91,6 +91,16 @@ Please try to avoid leaving `TODO`s in the code. There are a few around, but I wish there weren't. You can leave `FIXME`s, preferably with an issue number. +### Run Rustfmt from source code + +You may want to run a version of rustfmt from source code as part of a test or +hacking on the rustfmt codebase. It's strongly discouraged to install a version +of rustfmt from source. Instead, run it using `cargo run`, and `--manifest-path`. + +``` +cargo run --bin cargo-fmt -- --manifest-path path/to/project/you/want2test/Cargo.toml +``` + ### Version-gate formatting changes A change that introduces a different code-formatting should be gated on the diff --git a/src/tools/rustfmt/README.md b/src/tools/rustfmt/README.md index 0f9652aecf9..c05184fbb04 100644 --- a/src/tools/rustfmt/README.md +++ b/src/tools/rustfmt/README.md @@ -1,4 +1,4 @@ -# rustfmt [](https://travis-ci.com/rust-lang/rustfmt) [](https://ci.appveyor.com/project/rust-lang-libs/rustfmt) [](https://crates.io/crates/rustfmt-nightly) [](https://travis-ci.org/davidalber/rustfmt-travis) +# rustfmt [](https://github.com/rust-lang/rustfmt/actions/workflows/linux.yml) [](https://github.com/rust-lang/rustfmt/actions/workflows/mac.yml) [](https://github.com/rust-lang/rustfmt/actions/workflows/windows.yml) [](https://crates.io/crates/rustfmt-nightly) A tool for formatting Rust code according to style guidelines. @@ -7,9 +7,7 @@ If you'd like to help out (and you should, it's a fun project!), see Conduct](CODE_OF_CONDUCT.md). You can use rustfmt in Travis CI builds. We provide a minimal Travis CI -configuration (see [here](#checking-style-on-a-ci-server)) and verify its status -using another repository. The status of that repository's build is reported by -the "travis example" badge above. +configuration (see [here](#checking-style-on-a-ci-server)). ## Quick start @@ -73,24 +71,6 @@ because in the future Rustfmt might work on code where it currently does not): fixes to break our stability guarantees). -## Installation - -```sh -rustup component add rustfmt -``` - -## Installing from source - -To install from source (nightly required), first checkout to the tag or branch you want to install, then issue - -```sh -cargo install --path . -``` - -This will install `rustfmt` in your `~/.cargo/bin`. Make sure to add `~/.cargo/bin` directory to -your PATH variable. - - ## Running You can run Rustfmt by just typing `rustfmt filename` if you used `cargo diff --git a/src/tools/rustfmt/config_proc_macro/Cargo.lock b/src/tools/rustfmt/config_proc_macro/Cargo.lock index 49f2f72a8d2..7af746f0c96 100644 --- a/src/tools/rustfmt/config_proc_macro/Cargo.lock +++ b/src/tools/rustfmt/config_proc_macro/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "proc-macro2" -version = "1.0.3" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.2" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] @@ -32,18 +32,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.99" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.99" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4dc18c61206b08dc98216c98faa0232f4337e1e1b8574551d5bad29ea1b425" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", @@ -52,17 +52,17 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.5" +version = "2.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" +checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] -name = "unicode-xid" -version = "0.2.0" +name = "unicode-ident" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" diff --git a/src/tools/rustfmt/config_proc_macro/Cargo.toml b/src/tools/rustfmt/config_proc_macro/Cargo.toml index d10d0469cc4..34e8c237f55 100644 --- a/src/tools/rustfmt/config_proc_macro/Cargo.toml +++ b/src/tools/rustfmt/config_proc_macro/Cargo.toml @@ -13,10 +13,10 @@ proc-macro = true [dependencies] proc-macro2 = "1.0" quote = "1.0" -syn = { version = "1.0", features = ["full", "visit"] } +syn = { version = "2.0", features = ["full", "visit"] } [dev-dependencies] -serde = { version = "1.0", features = ["derive"] } +serde = { version = "1.0.160", features = ["derive"] } [features] default = [] diff --git a/src/tools/rustfmt/config_proc_macro/src/attrs.rs b/src/tools/rustfmt/config_proc_macro/src/attrs.rs index dd18ff572cb..d8de9aae088 100644 --- a/src/tools/rustfmt/config_proc_macro/src/attrs.rs +++ b/src/tools/rustfmt/config_proc_macro/src/attrs.rs @@ -51,26 +51,26 @@ pub fn is_unstable_variant(attr: &syn::Attribute) -> bool { } fn is_attr_name_value(attr: &syn::Attribute, name: &str) -> bool { - attr.parse_meta().ok().map_or(false, |meta| match meta { - syn::Meta::NameValue(syn::MetaNameValue { ref path, .. }) if path.is_ident(name) => true, + match &attr.meta { + syn::Meta::NameValue(syn::MetaNameValue { path, .. }) if path.is_ident(name) => true, _ => false, - }) + } } fn is_attr_path(attr: &syn::Attribute, name: &str) -> bool { - attr.parse_meta().ok().map_or(false, |meta| match meta { + match &attr.meta { syn::Meta::Path(path) if path.is_ident(name) => true, _ => false, - }) + } } fn get_name_value_str_lit(attr: &syn::Attribute, name: &str) -> Option<String> { - attr.parse_meta().ok().and_then(|meta| match meta { + match &attr.meta { syn::Meta::NameValue(syn::MetaNameValue { - ref path, - lit: syn::Lit::Str(ref lit_str), + path, + value: syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Str(lit_str), .. }), .. }) if path.is_ident(name) => Some(lit_str.value()), _ => None, - }) + } } diff --git a/src/tools/rustfmt/rust-toolchain b/src/tools/rustfmt/rust-toolchain index 22283b3d620..03b909cd80c 100644 --- a/src/tools/rustfmt/rust-toolchain +++ b/src/tools/rustfmt/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-01-24" +channel = "nightly-2023-06-19" components = ["llvm-tools", "rustc-dev"] diff --git a/src/tools/rustfmt/src/attr/doc_comment.rs b/src/tools/rustfmt/src/attr/doc_comment.rs index f653a12a8af..25c8158df8c 100644 --- a/src/tools/rustfmt/src/attr/doc_comment.rs +++ b/src/tools/rustfmt/src/attr/doc_comment.rs @@ -2,12 +2,17 @@ use crate::comment::CommentStyle; use std::fmt::{self, Display}; /// Formats a string as a doc comment using the given [`CommentStyle`]. -#[derive(new)] pub(super) struct DocCommentFormatter<'a> { literal: &'a str, style: CommentStyle<'a>, } +impl<'a> DocCommentFormatter<'a> { + pub(super) const fn new(literal: &'a str, style: CommentStyle<'a>) -> Self { + Self { literal, style } + } +} + impl Display for DocCommentFormatter<'_> { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { let opener = self.style.opener().trim_end(); diff --git a/src/tools/rustfmt/src/bin/main.rs b/src/tools/rustfmt/src/bin/main.rs index 47846424b06..03b75c1b041 100644 --- a/src/tools/rustfmt/src/bin/main.rs +++ b/src/tools/rustfmt/src/bin/main.rs @@ -84,7 +84,7 @@ pub enum OperationError { #[error("{0}")] IoError(IoError), /// Attempt to use --emit with a mode which is not currently - /// supported with stdandard input. + /// supported with standard input. #[error("Emit mode {0} not supported with standard output.")] StdinBadEmit(EmitMode), } diff --git a/src/tools/rustfmt/src/cargo-fmt/main.rs b/src/tools/rustfmt/src/cargo-fmt/main.rs index 2b714b68df0..bc9745275f2 100644 --- a/src/tools/rustfmt/src/cargo-fmt/main.rs +++ b/src/tools/rustfmt/src/cargo-fmt/main.rs @@ -14,7 +14,8 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::str; -use clap::{AppSettings, CommandFactory, Parser}; +use cargo_metadata::Edition; +use clap::{CommandFactory, Parser}; #[path = "test/mod.rs"] #[cfg(test)] @@ -22,7 +23,7 @@ mod cargo_fmt_tests; #[derive(Parser)] #[clap( - global_setting(AppSettings::NoAutoVersion), + disable_version_flag = true, bin_name = "cargo fmt", about = "This utility formats all bin and lib files of \ the current crate using rustfmt." @@ -45,7 +46,7 @@ pub struct Opts { short = 'p', long = "package", value_name = "package", - multiple_values = true + num_args = 1.. )] packages: Vec<String>, @@ -270,7 +271,7 @@ pub struct Target { /// A kind of target (e.g., lib, bin, example, ...). kind: String, /// Rust edition for this target. - edition: String, + edition: Edition, } impl Target { @@ -281,7 +282,7 @@ impl Target { Target { path: canonicalized, kind: target.kind[0].clone(), - edition: target.edition.clone(), + edition: target.edition, } } } @@ -506,7 +507,7 @@ fn run_rustfmt( let mut command = rustfmt_command() .stdout(stdout) .args(files) - .args(&["--edition", edition]) + .args(&["--edition", edition.as_str()]) .args(fmt_args) .spawn() .map_err(|e| match e.kind() { diff --git a/src/tools/rustfmt/src/cargo-fmt/test/targets.rs b/src/tools/rustfmt/src/cargo-fmt/test/targets.rs index b7e7fabdf71..34accb2136a 100644 --- a/src/tools/rustfmt/src/cargo-fmt/test/targets.rs +++ b/src/tools/rustfmt/src/cargo-fmt/test/targets.rs @@ -2,7 +2,7 @@ use super::*; struct ExpTarget { path: &'static str, - edition: &'static str, + edition: Edition, kind: &'static str, } @@ -26,7 +26,7 @@ mod all_targets { for target in exp_targets { assert!(targets.contains(&Target { path: get_path(target.path), - edition: target.edition.to_owned(), + edition: target.edition, kind: target.kind.to_owned(), })); } @@ -39,17 +39,17 @@ mod all_targets { let exp_targets = vec![ ExpTarget { path: "dependency-dir-name/subdep-dir-name/src/lib.rs", - edition: "2018", + edition: Edition::E2018, kind: "lib", }, ExpTarget { path: "dependency-dir-name/src/lib.rs", - edition: "2018", + edition: Edition::E2018, kind: "lib", }, ExpTarget { path: "src/main.rs", - edition: "2018", + edition: Edition::E2018, kind: "main", }, ]; @@ -79,32 +79,32 @@ mod all_targets { let exp_targets = vec![ ExpTarget { path: "ws/a/src/main.rs", - edition: "2018", + edition: Edition::E2018, kind: "bin", }, ExpTarget { path: "ws/b/src/main.rs", - edition: "2018", + edition: Edition::E2018, kind: "bin", }, ExpTarget { path: "ws/c/src/lib.rs", - edition: "2018", + edition: Edition::E2018, kind: "lib", }, ExpTarget { path: "ws/a/d/src/lib.rs", - edition: "2018", + edition: Edition::E2018, kind: "lib", }, ExpTarget { path: "e/src/main.rs", - edition: "2018", + edition: Edition::E2018, kind: "main", }, ExpTarget { path: "ws/a/d/f/src/lib.rs", - edition: "2018", + edition: Edition::E2018, kind: "lib", }, ]; diff --git a/src/tools/rustfmt/src/comment.rs b/src/tools/rustfmt/src/comment.rs index 4d565afc1e0..85918ecc116 100644 --- a/src/tools/rustfmt/src/comment.rs +++ b/src/tools/rustfmt/src/comment.rs @@ -432,12 +432,18 @@ impl CodeBlockAttribute { /// Block that is formatted as an item. /// -/// An item starts with either a star `*` a dash `-` or a greater-than `>`. +/// An item starts with either a star `*`, a dash `-`, a greater-than `>`, a plus '+', or a number +/// `12.` or `34)` (with at most 2 digits). An item represents CommonMark's ["list +/// items"](https://spec.commonmark.org/0.30/#list-items) and/or ["block +/// quotes"](https://spec.commonmark.org/0.30/#block-quotes), but note that only a subset of +/// CommonMark is recognized - see the doc comment of [`ItemizedBlock::get_marker_length`] for more +/// details. +/// /// Different level of indentation are handled by shrinking the shape accordingly. struct ItemizedBlock { /// the lines that are identified as part of an itemized block lines: Vec<String>, - /// the number of characters (typically whitespaces) up to the item sigil + /// the number of characters (typically whitespaces) up to the item marker indent: usize, /// the string that marks the start of an item opener: String, @@ -446,36 +452,70 @@ struct ItemizedBlock { } impl ItemizedBlock { - /// Returns `true` if the line is formatted as an item - fn is_itemized_line(line: &str) -> bool { - let trimmed = line.trim_start(); - trimmed.starts_with("* ") || trimmed.starts_with("- ") || trimmed.starts_with("> ") - } - - /// Creates a new ItemizedBlock described with the given line. - /// The `is_itemized_line` needs to be called first. - fn new(line: &str) -> ItemizedBlock { - let space_to_sigil = line.chars().take_while(|c| c.is_whitespace()).count(); - // +2 = '* ', which will add the appropriate amount of whitespace to keep itemized - // content formatted correctly. - let mut indent = space_to_sigil + 2; + /// Checks whether the `trimmed` line includes an item marker. Returns `None` if there is no + /// marker. Returns the length of the marker (in bytes) if one is present. Note that the length + /// includes the whitespace that follows the marker, for example the marker in `"* list item"` + /// has the length of 2. + /// + /// This function recognizes item markers that correspond to CommonMark's + /// ["bullet list marker"](https://spec.commonmark.org/0.30/#bullet-list-marker), + /// ["block quote marker"](https://spec.commonmark.org/0.30/#block-quote-marker), and/or + /// ["ordered list marker"](https://spec.commonmark.org/0.30/#ordered-list-marker). + /// + /// Compared to CommonMark specification, the number of digits that are allowed in an ["ordered + /// list marker"](https://spec.commonmark.org/0.30/#ordered-list-marker) is more limited (to at + /// most 2 digits). Limiting the length of the marker helps reduce the risk of recognizing + /// arbitrary numbers as markers. See also + /// <https://talk.commonmark.org/t/blank-lines-before-lists-revisited/1990> which gives the + /// following example where a number (i.e. "1868") doesn't signify an ordered list: + /// ```md + /// The Captain died in + /// 1868. He wes buried in... + /// ``` + fn get_marker_length(trimmed: &str) -> Option<usize> { + // https://spec.commonmark.org/0.30/#bullet-list-marker or + // https://spec.commonmark.org/0.30/#block-quote-marker + let itemized_start = ["* ", "- ", "> ", "+ "]; + if itemized_start.iter().any(|s| trimmed.starts_with(s)) { + return Some(2); // All items in `itemized_start` have length 2. + } + + // https://spec.commonmark.org/0.30/#ordered-list-marker, where at most 2 digits are + // allowed. + for suffix in [". ", ") "] { + if let Some((prefix, _)) = trimmed.split_once(suffix) { + if prefix.len() <= 2 && prefix.chars().all(|c| char::is_ascii_digit(&c)) { + return Some(prefix.len() + suffix.len()); + } + } + } + + None // No markers found. + } + + /// Creates a new `ItemizedBlock` described with the given `line`. + /// Returns `None` if `line` doesn't start an item. + fn new(line: &str) -> Option<ItemizedBlock> { + let marker_length = ItemizedBlock::get_marker_length(line.trim_start())?; + let space_to_marker = line.chars().take_while(|c| c.is_whitespace()).count(); + let mut indent = space_to_marker + marker_length; let mut line_start = " ".repeat(indent); // Markdown blockquote start with a "> " if line.trim_start().starts_with(">") { // remove the original +2 indent because there might be multiple nested block quotes // and it's easier to reason about the final indent by just taking the length - // of th new line_start. We update the indent because it effects the max width + // of the new line_start. We update the indent because it effects the max width // of each formatted line. line_start = itemized_block_quote_start(line, line_start, 2); indent = line_start.len(); } - ItemizedBlock { + Some(ItemizedBlock { lines: vec![line[indent..].to_string()], indent, opener: line[..indent].to_string(), line_start, - } + }) } /// Returns a `StringFormat` used for formatting the content of an item. @@ -494,7 +534,7 @@ impl ItemizedBlock { /// Returns `true` if the line is part of the current itemized block. /// If it is, then it is added to the internal lines list. fn add_line(&mut self, line: &str) -> bool { - if !ItemizedBlock::is_itemized_line(line) + if ItemizedBlock::get_marker_length(line.trim_start()).is_none() && self.indent <= line.chars().take_while(|c| c.is_whitespace()).count() { self.lines.push(line.to_string()); @@ -726,7 +766,7 @@ impl<'a> CommentRewrite<'a> { let code_block = match self.code_block_attr.as_ref().unwrap() { CodeBlockAttribute::Rust if self.fmt.config.format_code_in_doc_comments() - && !self.code_block_buffer.is_empty() => + && !self.code_block_buffer.trim().is_empty() => { let mut config = self.fmt.config.clone(); config.set().wrap_comments(false); @@ -765,10 +805,11 @@ impl<'a> CommentRewrite<'a> { self.item_block = None; if let Some(stripped) = line.strip_prefix("```") { self.code_block_attr = Some(CodeBlockAttribute::new(stripped)) - } else if self.fmt.config.wrap_comments() && ItemizedBlock::is_itemized_line(line) { - let ib = ItemizedBlock::new(line); - self.item_block = Some(ib); - return false; + } else if self.fmt.config.wrap_comments() { + if let Some(ib) = ItemizedBlock::new(line) { + self.item_block = Some(ib); + return false; + } } if self.result == self.opener { @@ -801,10 +842,13 @@ impl<'a> CommentRewrite<'a> { // 2) The comment is not the start of a markdown header doc comment // 3) The comment width exceeds the shape's width // 4) No URLS were found in the comment + // If this changes, the documentation in ../Configurations.md#wrap_comments + // should be changed accordingly. let should_wrap_comment = self.fmt.config.wrap_comments() && !is_markdown_header_doc_comment && unicode_str_width(line) > self.fmt.shape.width - && !has_url(line); + && !has_url(line) + && !is_table_item(line); if should_wrap_comment { match rewrite_string(line, &self.fmt, self.max_width) { @@ -939,6 +983,18 @@ fn has_url(s: &str) -> bool { || REFERENCE_LINK_URL.is_match(s) } +/// Returns true if the given string may be part of a Markdown table. +fn is_table_item(mut s: &str) -> bool { + // This function may return false positive, but should get its job done in most cases (i.e. + // markdown tables with two column delimiters). + s = s.trim_start(); + return s.starts_with('|') + && match s.rfind('|') { + Some(0) | None => false, + _ => true, + }; +} + /// Given the span, rewrite the missing comment inside it if available. /// Note that the given span must only include comments (or leading/trailing whitespaces). pub(crate) fn rewrite_missing_comment( @@ -2004,4 +2060,96 @@ fn main() { "#; assert_eq!(s, filter_normal_code(s_with_comment)); } + + #[test] + fn test_itemized_block_first_line_handling() { + fn run_test( + test_input: &str, + expected_line: &str, + expected_indent: usize, + expected_opener: &str, + expected_line_start: &str, + ) { + let block = ItemizedBlock::new(test_input).unwrap(); + assert_eq!(1, block.lines.len(), "test_input: {:?}", test_input); + assert_eq!( + expected_line, &block.lines[0], + "test_input: {:?}", + test_input + ); + assert_eq!( + expected_indent, block.indent, + "test_input: {:?}", + test_input + ); + assert_eq!( + expected_opener, &block.opener, + "test_input: {:?}", + test_input + ); + assert_eq!( + expected_line_start, &block.line_start, + "test_input: {:?}", + test_input + ); + } + + run_test("- foo", "foo", 2, "- ", " "); + run_test("* foo", "foo", 2, "* ", " "); + run_test("> foo", "foo", 2, "> ", "> "); + + run_test("1. foo", "foo", 3, "1. ", " "); + run_test("12. foo", "foo", 4, "12. ", " "); + run_test("1) foo", "foo", 3, "1) ", " "); + run_test("12) foo", "foo", 4, "12) ", " "); + + run_test(" - foo", "foo", 6, " - ", " "); + + // https://spec.commonmark.org/0.30 says: "A start number may begin with 0s": + run_test("0. foo", "foo", 3, "0. ", " "); + run_test("01. foo", "foo", 4, "01. ", " "); + } + + #[test] + fn test_itemized_block_nonobvious_markers_are_rejected() { + let test_inputs = vec![ + // Non-numeric item markers (e.g. `a.` or `iv.`) are not allowed by + // https://spec.commonmark.org/0.30/#ordered-list-marker. We also note that allowing + // them would risk misidentifying regular words as item markers. See also the + // discussion in https://talk.commonmark.org/t/blank-lines-before-lists-revisited/1990 + "word. rest of the paragraph.", + "a. maybe this is a list item? maybe not?", + "iv. maybe this is a list item? maybe not?", + // Numbers with 3 or more digits are not recognized as item markers, to avoid + // formatting the following example as a list: + // + // ``` + // The Captain died in + // 1868. He was buried in... + // ``` + "123. only 2-digit numbers are recognized as item markers.", + // Parens: + "123) giving some coverage to parens as well.", + "a) giving some coverage to parens as well.", + // https://spec.commonmark.org/0.30 says that "at least one space or tab is needed + // between the list marker and any following content": + "1.Not a list item.", + "1.2.3. Not a list item.", + "1)Not a list item.", + "-Not a list item.", + "+Not a list item.", + "+1 not a list item.", + // https://spec.commonmark.org/0.30 says: "A start number may not be negative": + "-1. Not a list item.", + "-1 Not a list item.", + ]; + for line in test_inputs.iter() { + let maybe_block = ItemizedBlock::new(line); + assert!( + maybe_block.is_none(), + "The following line shouldn't be classified as a list item: {}", + line + ); + } + } } diff --git a/src/tools/rustfmt/src/config/options.rs b/src/tools/rustfmt/src/config/options.rs index 257a17b2703..408017d2432 100644 --- a/src/tools/rustfmt/src/config/options.rs +++ b/src/tools/rustfmt/src/config/options.rs @@ -18,7 +18,7 @@ pub enum NewlineStyle { Auto, /// Force CRLF (`\r\n`). Windows, - /// Force CR (`\n). + /// Force CR (`\n`). Unix, /// `\r\n` in Windows, `\n` on other platforms. Native, diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 5dc628adb0c..5600f7778f2 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -232,6 +232,7 @@ pub(crate) fn format_expr( ast::ExprKind::Ret(Some(ref expr)) => { rewrite_unary_prefix(context, "return ", &**expr, shape) } + ast::ExprKind::Become(ref expr) => rewrite_unary_prefix(context, "become ", &**expr, shape), ast::ExprKind::Yeet(None) => Some("do yeet".to_owned()), ast::ExprKind::Yeet(Some(ref expr)) => { rewrite_unary_prefix(context, "do yeet ", &**expr, shape) @@ -1724,9 +1725,11 @@ pub(crate) fn rewrite_field( let overhead = name.len() + separator.len(); let expr_shape = shape.offset_left(overhead)?; let expr = field.expr.rewrite(context, expr_shape); - + let is_lit = matches!(field.expr.kind, ast::ExprKind::Lit(_)); match expr { - Some(ref e) if e.as_str() == name && context.config.use_field_init_shorthand() => { + Some(ref e) + if !is_lit && e.as_str() == name && context.config.use_field_init_shorthand() => + { Some(attrs_str + name) } Some(e) => Some(format!("{}{}{}{}", attrs_str, name, separator, e)), diff --git a/src/tools/rustfmt/src/formatting.rs b/src/tools/rustfmt/src/formatting.rs index 1dfd8a514f0..1f4ad6960e2 100644 --- a/src/tools/rustfmt/src/formatting.rs +++ b/src/tools/rustfmt/src/formatting.rs @@ -175,7 +175,6 @@ fn format_project<T: FormatHandler>( } // Used for formatting files. -#[derive(new)] struct FormatContext<'a, T: FormatHandler> { krate: &'a ast::Crate, report: FormatReport, @@ -185,6 +184,22 @@ struct FormatContext<'a, T: FormatHandler> { } impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> { + fn new( + krate: &'a ast::Crate, + report: FormatReport, + parse_session: ParseSess, + config: &'a Config, + handler: &'a mut T, + ) -> Self { + FormatContext { + krate, + report, + parse_session, + config, + handler, + } + } + fn ignore_file(&self, path: &FileName) -> bool { self.parse_session.ignore_file(path) } diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 43779cfaecd..3ecdb5b4c60 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -560,7 +560,7 @@ impl<'a> FmtVisitor<'a> { let variant_body = match field.data { ast::VariantData::Tuple(..) | ast::VariantData::Struct(..) => format_struct( &context, - &StructParts::from_variant(field), + &StructParts::from_variant(field, &context), self.block_indent, Some(one_line_width), )?, @@ -951,14 +951,14 @@ impl<'a> StructParts<'a> { format_header(context, self.prefix, self.ident, self.vis, offset) } - fn from_variant(variant: &'a ast::Variant) -> Self { + fn from_variant(variant: &'a ast::Variant, context: &RewriteContext<'_>) -> Self { StructParts { prefix: "", ident: variant.ident, vis: &DEFAULT_VISIBILITY, def: &variant.data, generics: None, - span: variant.span, + span: enum_variant_span(variant, context), } } @@ -979,6 +979,25 @@ impl<'a> StructParts<'a> { } } +fn enum_variant_span(variant: &ast::Variant, context: &RewriteContext<'_>) -> Span { + use ast::VariantData::*; + if let Some(ref anon_const) = variant.disr_expr { + let span_before_consts = variant.span.until(anon_const.value.span); + let hi = match &variant.data { + Struct(..) => context + .snippet_provider + .span_after_last(span_before_consts, "}"), + Tuple(..) => context + .snippet_provider + .span_after_last(span_before_consts, ")"), + Unit(..) => variant.ident.span.hi(), + }; + mk_sp(span_before_consts.lo(), hi) + } else { + variant.span + } +} + fn format_struct( context: &RewriteContext<'_>, struct_parts: &StructParts<'_>, @@ -1278,7 +1297,7 @@ pub(crate) fn format_struct_struct( let header_hi = struct_parts.ident.span.hi(); let body_lo = if let Some(generics) = struct_parts.generics { // Adjust the span to start at the end of the generic arguments before searching for the '{' - let span = span.with_lo(generics.span.hi()); + let span = span.with_lo(generics.where_clause.span.hi()); context.snippet_provider.span_after(span, "{") } else { context.snippet_provider.span_after(span, "{") diff --git a/src/tools/rustfmt/src/lib.rs b/src/tools/rustfmt/src/lib.rs index b27405efdb7..567628f63bd 100644 --- a/src/tools/rustfmt/src/lib.rs +++ b/src/tools/rustfmt/src/lib.rs @@ -5,8 +5,6 @@ #![allow(clippy::match_like_matches_macro)] #![allow(unreachable_pub)] -#[macro_use] -extern crate derive_new; #[cfg(test)] #[macro_use] extern crate lazy_static; diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs index 7978d8cba95..e9a298a2769 100644 --- a/src/tools/rustfmt/src/macros.rs +++ b/src/tools/rustfmt/src/macros.rs @@ -1119,12 +1119,15 @@ pub(crate) fn macro_style(mac: &ast::MacCall, context: &RewriteContext<'_>) -> D // A very simple parser that just parses a macros 2.0 definition into its branches. // Currently we do not attempt to parse any further than that. -#[derive(new)] struct MacroParser { toks: TokenTreeCursor, } impl MacroParser { + const fn new(toks: TokenTreeCursor) -> Self { + Self { toks } + } + // (`(` ... `)` `=>` `{` ... `}`)* fn parse(&mut self) -> Option<Macro> { let mut branches = vec![]; diff --git a/src/tools/rustfmt/src/overflow.rs b/src/tools/rustfmt/src/overflow.rs index af0b95430a1..d81bf24dbd1 100644 --- a/src/tools/rustfmt/src/overflow.rs +++ b/src/tools/rustfmt/src/overflow.rs @@ -589,6 +589,8 @@ impl<'a> Context<'a> { fn rewrite_items(&self) -> Option<(bool, String)> { let span = self.items_span(); + debug!("items: {:?}", self.items); + let items = itemize_list( self.context.snippet_provider, self.items.iter(), @@ -603,6 +605,8 @@ impl<'a> Context<'a> { ); let mut list_items: Vec<_> = items.collect(); + debug!("items: {list_items:?}"); + // Try letting the last argument overflow to the next line with block // indentation. If its first line fits on one line with the other arguments, // we format the function arguments horizontally. diff --git a/src/tools/rustfmt/src/pairs.rs b/src/tools/rustfmt/src/pairs.rs index d1c75126ea4..d135da7e359 100644 --- a/src/tools/rustfmt/src/pairs.rs +++ b/src/tools/rustfmt/src/pairs.rs @@ -9,7 +9,7 @@ use crate::utils::{ }; /// Sigils that decorate a binop pair. -#[derive(new, Clone, Copy)] +#[derive(Clone, Copy)] pub(crate) struct PairParts<'a> { prefix: &'a str, infix: &'a str, @@ -17,6 +17,13 @@ pub(crate) struct PairParts<'a> { } impl<'a> PairParts<'a> { + pub(crate) const fn new(prefix: &'a str, infix: &'a str, suffix: &'a str) -> Self { + Self { + prefix, + infix, + suffix, + } + } pub(crate) fn infix(infix: &'a str) -> PairParts<'a> { PairParts { prefix: "", diff --git a/src/tools/rustfmt/src/parse/macros/cfg_if.rs b/src/tools/rustfmt/src/parse/macros/cfg_if.rs index ace1a76b3fe..cbc4c90b8f9 100644 --- a/src/tools/rustfmt/src/parse/macros/cfg_if.rs +++ b/src/tools/rustfmt/src/parse/macros/cfg_if.rs @@ -34,6 +34,11 @@ fn parse_cfg_if_inner<'a>( if !parser.eat_keyword(kw::If) { return Err("Expected `if`"); } + + if !matches!(parser.token.kind, TokenKind::Pound) { + return Err("Failed to parse attributes"); + } + // Inner attributes are not actually syntactically permitted here, but we don't // care about inner vs outer attributes in this position. Our purpose with this // special case parsing of cfg_if macros is to ensure we can correctly resolve @@ -44,7 +49,10 @@ fn parse_cfg_if_inner<'a>( // See also https://github.com/rust-lang/rust/pull/79433 parser .parse_attribute(rustc_parse::parser::attr::InnerAttrPolicy::Permitted) - .map_err(|_| "Failed to parse attributes")?; + .map_err(|e| { + e.cancel(); + "Failed to parse attributes" + })?; } if !parser.eat(&TokenKind::OpenDelim(Delimiter::Brace)) { diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index a64963db6a7..81b5015dde3 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -12,6 +12,7 @@ use rustc_span::{ }; use crate::config::file_lines::LineRange; +use crate::config::options::Color; use crate::ignore_path::IgnorePathSet; use crate::parse::parser::{ModError, ModulePathSuccess}; use crate::source_map::LineRangeUtils; @@ -107,15 +108,26 @@ impl Emitter for SilentOnIgnoredFilesEmitter { } } +impl From<Color> for ColorConfig { + fn from(color: Color) -> Self { + match color { + Color::Auto => ColorConfig::Auto, + Color::Always => ColorConfig::Always, + Color::Never => ColorConfig::Never, + } + } +} + fn default_handler( source_map: Lrc<SourceMap>, ignore_path_set: Lrc<IgnorePathSet>, can_reset: Lrc<AtomicBool>, hide_parse_errors: bool, + color: Color, ) -> Handler { let supports_color = term::stderr().map_or(false, |term| term.supports_color()); - let color_cfg = if supports_color { - ColorConfig::Auto + let emit_color = if supports_color { + ColorConfig::from(color) } else { ColorConfig::Never }; @@ -128,7 +140,7 @@ fn default_handler( false, ); Box::new(EmitterWriter::stderr( - color_cfg, + emit_color, Some(source_map.clone()), None, fallback_bundle, @@ -167,6 +179,7 @@ impl ParseSess { Lrc::clone(&ignore_path_set), Lrc::clone(&can_reset_errors), config.hide_parse_errors(), + config.color(), ); let parse_sess = RawParseSess::with_span_handler(handler, source_map); diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index f548388ed8b..18a08f17ba0 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -578,49 +578,41 @@ impl Rewrite for ast::GenericBounds { impl Rewrite for ast::GenericParam { fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> { - let mut result = String::with_capacity(128); // FIXME: If there are more than one attributes, this will force multiline. - match self.attrs.rewrite(context, shape) { - Some(ref rw) if !rw.is_empty() => { - result.push_str(rw); - // When rewriting generic params, an extra newline should be put - // if the attributes end with a doc comment - if let Some(true) = self.attrs.last().map(|a| a.is_doc_comment()) { - result.push_str(&shape.indent.to_string_with_newline(context.config)); - } else { - result.push(' '); - } - } - _ => (), - } + let mut result = self.attrs.rewrite(context, shape).unwrap_or(String::new()); + let has_attrs = !result.is_empty(); - if let ast::GenericParamKind::Const { + let mut param = String::with_capacity(128); + + let param_start = if let ast::GenericParamKind::Const { ref ty, - kw_span: _, + kw_span, default, } = &self.kind { - result.push_str("const "); - result.push_str(rewrite_ident(context, self.ident)); - result.push_str(": "); - result.push_str(&ty.rewrite(context, shape)?); + param.push_str("const "); + param.push_str(rewrite_ident(context, self.ident)); + param.push_str(": "); + param.push_str(&ty.rewrite(context, shape)?); if let Some(default) = default { let eq_str = match context.config.type_punctuation_density() { TypeDensity::Compressed => "=", TypeDensity::Wide => " = ", }; - result.push_str(eq_str); - let budget = shape.width.checked_sub(result.len())?; + param.push_str(eq_str); + let budget = shape.width.checked_sub(param.len())?; let rewrite = default.rewrite(context, Shape::legacy(budget, shape.indent))?; - result.push_str(&rewrite); + param.push_str(&rewrite); } + kw_span.lo() } else { - result.push_str(rewrite_ident(context, self.ident)); - } + param.push_str(rewrite_ident(context, self.ident)); + self.ident.span.lo() + }; if !self.bounds.is_empty() { - result.push_str(type_bound_colon(context)); - result.push_str(&self.bounds.rewrite(context, shape)?) + param.push_str(type_bound_colon(context)); + param.push_str(&self.bounds.rewrite(context, shape)?) } if let ast::GenericParamKind::Type { default: Some(ref def), @@ -630,11 +622,33 @@ impl Rewrite for ast::GenericParam { TypeDensity::Compressed => "=", TypeDensity::Wide => " = ", }; - result.push_str(eq_str); - let budget = shape.width.checked_sub(result.len())?; + param.push_str(eq_str); + let budget = shape.width.checked_sub(param.len())?; let rewrite = - def.rewrite(context, Shape::legacy(budget, shape.indent + result.len()))?; - result.push_str(&rewrite); + def.rewrite(context, Shape::legacy(budget, shape.indent + param.len()))?; + param.push_str(&rewrite); + } + + if let Some(last_attr) = self.attrs.last().filter(|last_attr| { + contains_comment(context.snippet(mk_sp(last_attr.span.hi(), param_start))) + }) { + result = combine_strs_with_missing_comments( + context, + &result, + ¶m, + mk_sp(last_attr.span.hi(), param_start), + shape, + !last_attr.is_doc_comment(), + )?; + } else { + // When rewriting generic params, an extra newline should be put + // if the attributes end with a doc comment + if let Some(true) = self.attrs.last().map(|a| a.is_doc_comment()) { + result.push_str(&shape.indent.to_string_with_newline(context.config)); + } else if has_attrs { + result.push(' '); + } + result.push_str(¶m); } Some(result) diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index ca171657407..890a05b8c82 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -505,6 +505,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::Range(..) | ast::ExprKind::Repeat(..) | ast::ExprKind::Ret(..) + | ast::ExprKind::Become(..) | ast::ExprKind::Yeet(..) | ast::ExprKind::Tup(..) | ast::ExprKind::Type(..) diff --git a/src/tools/rustfmt/tests/rustfmt/main.rs b/src/tools/rustfmt/tests/rustfmt/main.rs index 7ff301e8019..4936a717463 100644 --- a/src/tools/rustfmt/tests/rustfmt/main.rs +++ b/src/tools/rustfmt/tests/rustfmt/main.rs @@ -174,3 +174,15 @@ fn rustfmt_emits_error_on_line_overflow_true() { "line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option)" )) } + +#[test] +#[allow(non_snake_case)] +fn dont_emit_ICE() { + let files = ["tests/target/issue_5728.rs", "tests/target/issue_5729.rs"]; + + for file in files { + let args = [file]; + let (_stdout, stderr) = rustfmt(&args); + assert!(!stderr.contains("thread 'main' panicked")); + } +} diff --git a/src/tools/rustfmt/tests/source/issue-4041.rs b/src/tools/rustfmt/tests/source/issue-4041.rs new file mode 100644 index 00000000000..274b80f1bc5 --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue-4041.rs @@ -0,0 +1,5 @@ +// rustfmt-wrap_comments: true +//! List: +//! - Sub list: +//! + very long #1 blah blah blah blah blah blah blah blah blah blah blah blah foo baar baxxxxxxxx long line 1231421230912i3091238192038 +//! + very long #2 blah blah blah blah blah blah blah blah blah blah blah blah diff --git a/src/tools/rustfmt/tests/source/issue-5234.rs b/src/tools/rustfmt/tests/source/issue-5234.rs new file mode 100644 index 00000000000..67266f485d3 --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue-5234.rs @@ -0,0 +1,51 @@ +// rustfmt-format_code_in_doc_comments: true + +/// ``` +/// ``` +fn foo() {} + +/// ``` +///Something +/// ``` +fn foo() {} + +/// ``` +/// +/// ``` +fn foo() {} + + +/// /// ``` +fn foo() {} + +/// /// ``` +/// ``` +/// +/// ``` +/// ``` +fn foo() {} + +fn foo() { +/// ``` +/// +/// ``` +struct bar {} +} + +/// ``` +/// fn com(){ +/// let i = 5; +/// +/// let j = 6; +/// } +/// ``` +fn foo() {} + +fn foo() { +/// ``` +///fn com(){ +///let i = 5; +///} +/// ``` +struct bar {} +} diff --git a/src/tools/rustfmt/tests/source/issue-5488.rs b/src/tools/rustfmt/tests/source/issue-5488.rs new file mode 100644 index 00000000000..d361632e29e --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue-5488.rs @@ -0,0 +1,17 @@ +// rustfmt-use_field_init_shorthand: true + +struct MyStruct(u32); +struct AnotherStruct { + a: u32, +} + +fn main() { + // Since MyStruct is a tuple struct, it should not be shorthanded to + // MyStruct { 0 } even if use_field_init_shorthand is enabled. + let instance = MyStruct { 0: 0 }; + + // Since AnotherStruct is not a tuple struct, the shorthand should + // apply. + let a = 10; + let instance = AnotherStruct { a: a }; +} diff --git a/src/tools/rustfmt/tests/source/issue-5586.rs b/src/tools/rustfmt/tests/source/issue-5586.rs new file mode 100644 index 00000000000..9cf6c1d58dd --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue-5586.rs @@ -0,0 +1,164 @@ +// rustfmt-version: Two +fn main() { + // sample 1 + { + { + { + { + { + let push_ident = + if let Some(&node_id) = subgraph_nodes.get(pull_to_push_idx) { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." +); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 2 + { + { + { + { + { + let push_ident = if let Some(&node_id) = + subgraph_nodes.get(pull_to_push_idx) + { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 3 + { + { + { + { + { + let push_ident = + if let Some(&node_id) = subgraph_nodes.get(pull_to_push_idx) { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 4 + {{{{{ + let push_ident = + if let Some(&node_id) = subgraph_nodes.get(pull_to_push_idx) { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + }}}}} + + // sample 5 + { + { + { + { + { + let push_ident = + if let Some(&node_id) = subgraph_nodes.get(pull_to_push_idx) { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 6 + { + { + { + { + { + let push_ident = if let Some(&node_id) = + subgraph_nodes.get(pull_to_push_idx) + { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 7 + { + { + { + { + { + let push_ident = + if let Some(&node_id) = subgraph_nodes.get(pull_to_push_idx) { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } +} diff --git a/src/tools/rustfmt/tests/source/issue_5686.rs b/src/tools/rustfmt/tests/source/issue_5686.rs new file mode 100644 index 00000000000..3bf96f73b2c --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue_5686.rs @@ -0,0 +1,40 @@ +#[repr(u8)] +enum MyEnum { + UnitWithExplicitDiscriminant = 0, + EmptyStructSingleLineBlockComment { + /* Comment */ + } = 1, + EmptyStructMultiLineBlockComment { + /* + * Comment + */ + } = 2, + EmptyStructLineComment { + // comment + } = 3, + EmptyTupleSingleLineBlockComment( + /* Comment */ + ) = 4, + EmptyTupleMultiLineBlockComment( + /* + * Comment + */ + ) = 5, + EmptyTupleLineComment( + // comment + ) = 6, +} + +enum Animal { + Dog(/* tuple variant closer in comment -> ) */) = 1, + #[hello(world)] + Cat(/* tuple variant close in leading attribute */) = 2, + Bee(/* tuple variant closer on associated field attribute */ #[hello(world)] usize) = 3, + Fox(/* tuple variant closer on const fn call */) = some_const_fn(), + Ant(/* tuple variant closer on macro call */) = some_macro!(), + Snake {/* stuct variant closer in comment -> } */} = 6, + #[hell{world}] + Cobra {/* struct variant close in leading attribute */} = 6, + Eagle {/* struct variant closer on associated field attribute */ #[hell{world}]value: Sting} = 7, + Koala {/* struct variant closer on macro call */} = some_macro!{} +} diff --git a/src/tools/rustfmt/tests/source/itemized-blocks/no_wrap.rs b/src/tools/rustfmt/tests/source/itemized-blocks/no_wrap.rs index a7b6a10a010..e5699e76684 100644 --- a/src/tools/rustfmt/tests/source/itemized-blocks/no_wrap.rs +++ b/src/tools/rustfmt/tests/source/itemized-blocks/no_wrap.rs @@ -1,7 +1,7 @@ // rustfmt-normalize_comments: true // rustfmt-format_code_in_doc_comments: true -//! This is a list: +//! This is an itemized markdown list (see also issue #3224): //! * Outer //! * Outer //! * Inner @@ -13,6 +13,40 @@ //! - when the log level is info, the level name is green and the rest of the line is white //! - when the log level is debug, the whole line is white //! - when the log level is trace, the whole line is gray ("bright black") +//! +//! This is a numbered markdown list (see also issue #5416): +//! 1. Long long long long long long long long long long long long long long long long long line +//! 2. Another very long long long long long long long long long long long long long long long line +//! 3. Nested list +//! 1. Long long long long long long long long long long long long long long long long line +//! 2. Another very long long long long long long long long long long long long long long line +//! 4. Last item +//! +//! Using the ')' instead of '.' character after the number: +//! 1) Long long long long long long long long long long long long long long long long long line +//! 2) Another very long long long long long long long long long long long long long long long line +//! +//! Deep list that mixes various bullet and number formats: +//! 1. First level with a long long long long long long long long long long long long long long +//! long long long line +//! 2. First level with another very long long long long long long long long long long long long +//! long long long line +//! * Second level with a long long long long long long long long long long long long long +//! long long long line +//! * Second level with another very long long long long long long long long long long long +//! long long long line +//! 1) Third level with a long long long long long long long long long long long long long +//! long long long line +//! 2) Third level with another very long long long long long long long long long long +//! long long long long line +//! - Forth level with a long long long long long long long long long long long long +//! long long long long line +//! - Forth level with another very long long long long long long long long long long +//! long long long long line +//! 3) One more item at the third level +//! 4) Last item of the third level +//! * Last item of second level +//! 3. Last item of first level /// All the parameters ***except for `from_theater`*** should be inserted as sent by the remote /// theater, i.e., as passed to [`Theater::send`] on the remote actor: diff --git a/src/tools/rustfmt/tests/source/itemized-blocks/wrap.rs b/src/tools/rustfmt/tests/source/itemized-blocks/wrap.rs index 955cc698b79..768461a43f9 100644 --- a/src/tools/rustfmt/tests/source/itemized-blocks/wrap.rs +++ b/src/tools/rustfmt/tests/source/itemized-blocks/wrap.rs @@ -2,7 +2,7 @@ // rustfmt-format_code_in_doc_comments: true // rustfmt-max_width: 50 -//! This is a list: +//! This is an itemized markdown list (see also issue #3224): //! * Outer //! * Outer //! * Inner @@ -14,6 +14,40 @@ //! - when the log level is info, the level name is green and the rest of the line is white //! - when the log level is debug, the whole line is white //! - when the log level is trace, the whole line is gray ("bright black") +//! +//! This is a numbered markdown list (see also issue #5416): +//! 1. Long long long long long long long long long long long long long long long long long line +//! 2. Another very long long long long long long long long long long long long long long long line +//! 3. Nested list +//! 1. Long long long long long long long long long long long long long long long long line +//! 2. Another very long long long long long long long long long long long long long long line +//! 4. Last item +//! +//! Using the ')' instead of '.' character after the number: +//! 1) Long long long long long long long long long long long long long long long long long line +//! 2) Another very long long long long long long long long long long long long long long long line +//! +//! Deep list that mixes various bullet and number formats: +//! 1. First level with a long long long long long long long long long long long long long long +//! long long long line +//! 2. First level with another very long long long long long long long long long long long long +//! long long long line +//! * Second level with a long long long long long long long long long long long long long +//! long long long line +//! * Second level with another very long long long long long long long long long long long +//! long long long line +//! 1) Third level with a long long long long long long long long long long long long long +//! long long long line +//! 2) Third level with another very long long long long long long long long long long +//! long long long long line +//! - Forth level with a long long long long long long long long long long long long +//! long long long long line +//! - Forth level with another very long long long long long long long long long long +//! long long long long line +//! 3) One more item at the third level +//! 4) Last item of the third level +//! * Last item of second level +//! 3. Last item of first level // This example shows how to configure fern to output really nicely colored logs // - when the log level is error, the whole line is red diff --git a/src/tools/rustfmt/tests/target/doc-of-generic-item.rs b/src/tools/rustfmt/tests/target/doc-of-generic-item.rs index 2efc5e09a3d..80886e74f83 100644 --- a/src/tools/rustfmt/tests/target/doc-of-generic-item.rs +++ b/src/tools/rustfmt/tests/target/doc-of-generic-item.rs @@ -12,3 +12,21 @@ struct Foo< /// doc of N const N: item, >; + +// Non-doc pre-comment of Foo +/// doc of Foo +// Non-doc post-comment of Foo +struct Foo< + // Non-doc pre-comment of 'a + /// doc of 'a + // Non-doc post-comment of 'a + 'a, + // Non-doc pre-comment of T + /// doc of T + // Non-doc post-comment of T + T, + // Non-doc pre-comment of N + /// doc of N + // Non-doc post-comment of N + const N: item, +>; diff --git a/src/tools/rustfmt/tests/target/issue-4041.rs b/src/tools/rustfmt/tests/target/issue-4041.rs new file mode 100644 index 00000000000..e9c693836f2 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-4041.rs @@ -0,0 +1,6 @@ +// rustfmt-wrap_comments: true +//! List: +//! - Sub list: +//! + very long #1 blah blah blah blah blah blah blah blah blah blah blah blah +//! foo baar baxxxxxxxx long line 1231421230912i3091238192038 +//! + very long #2 blah blah blah blah blah blah blah blah blah blah blah blah diff --git a/src/tools/rustfmt/tests/target/issue-4210-disabled.rs b/src/tools/rustfmt/tests/target/issue-4210-disabled.rs new file mode 100644 index 00000000000..3ba87aab8c5 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-4210-disabled.rs @@ -0,0 +1,15 @@ +// rustfmt-wrap_comments: false + +/// Table that is > 80 symbols: +/// +/// | table | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | +/// |-------|-----------------------------------------------------------------------------| +/// | val | x | +pub struct Item; + +/// Table value that is > 80 symbols: +/// +/// | table | heading +/// |----------|----------------------------------------------------------------------------- +/// | long val | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +pub struct Item2; diff --git a/src/tools/rustfmt/tests/target/issue-4210.rs b/src/tools/rustfmt/tests/target/issue-4210.rs new file mode 100644 index 00000000000..3fd96639082 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-4210.rs @@ -0,0 +1,15 @@ +// rustfmt-wrap_comments: true + +/// Table that is > 80 symbols: +/// +/// | table | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | +/// |-------|-----------------------------------------------------------------------------| +/// | val | x | +pub struct Item; + +/// Table value that is > 80 symbols: +/// +/// | table | heading +/// |----------|----------------------------------------------------------------------------- +/// | long val | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +pub struct Item2; diff --git a/src/tools/rustfmt/tests/target/issue-5234.rs b/src/tools/rustfmt/tests/target/issue-5234.rs new file mode 100644 index 00000000000..7ee9e46d1ef --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-5234.rs @@ -0,0 +1,47 @@ +// rustfmt-format_code_in_doc_comments: true + +/// ``` +/// ``` +fn foo() {} + +/// ``` +/// Something +/// ``` +fn foo() {} + +/// ``` +/// ``` +fn foo() {} + +/// /// ``` +fn foo() {} + +/// /// ``` +/// ``` +/// ``` +/// ``` +fn foo() {} + +fn foo() { + /// ``` + /// ``` + struct bar {} +} + +/// ``` +/// fn com() { +/// let i = 5; +/// +/// let j = 6; +/// } +/// ``` +fn foo() {} + +fn foo() { + /// ``` + /// fn com() { + /// let i = 5; + /// } + /// ``` + struct bar {} +} diff --git a/src/tools/rustfmt/tests/target/issue-5488.rs b/src/tools/rustfmt/tests/target/issue-5488.rs new file mode 100644 index 00000000000..0cb37c56f39 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-5488.rs @@ -0,0 +1,17 @@ +// rustfmt-use_field_init_shorthand: true + +struct MyStruct(u32); +struct AnotherStruct { + a: u32, +} + +fn main() { + // Since MyStruct is a tuple struct, it should not be shorthanded to + // MyStruct { 0 } even if use_field_init_shorthand is enabled. + let instance = MyStruct { 0: 0 }; + + // Since AnotherStruct is not a tuple struct, the shorthand should + // apply. + let a = 10; + let instance = AnotherStruct { a }; +} diff --git a/src/tools/rustfmt/tests/target/issue-5586.rs b/src/tools/rustfmt/tests/target/issue-5586.rs new file mode 100644 index 00000000000..7033ae975b3 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-5586.rs @@ -0,0 +1,177 @@ +// rustfmt-version: Two +fn main() { + // sample 1 + { + { + { + { + { + let push_ident = if let Some(&node_id) = + subgraph_nodes.get(pull_to_push_idx) + { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 2 + { + { + { + { + { + let push_ident = if let Some(&node_id) = + subgraph_nodes.get(pull_to_push_idx) + { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 3 + { + { + { + { + { + let push_ident = if let Some(&node_id) = + subgraph_nodes.get(pull_to_push_idx) + { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 4 + { + { + { + { + { + let push_ident = if let Some(&node_id) = + subgraph_nodes.get(pull_to_push_idx) + { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 5 + { + { + { + { + { + let push_ident = if let Some(&node_id) = + subgraph_nodes.get(pull_to_push_idx) + { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 6 + { + { + { + { + { + let push_ident = if let Some(&node_id) = + subgraph_nodes.get(pull_to_push_idx) + { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 7 + { + { + { + { + { + let push_ident = if let Some(&node_id) = + subgraph_nodes.get(pull_to_push_idx) + { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } +} diff --git a/src/tools/rustfmt/tests/target/issue_5686.rs b/src/tools/rustfmt/tests/target/issue_5686.rs new file mode 100644 index 00000000000..993f12b5316 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_5686.rs @@ -0,0 +1,42 @@ +#[repr(u8)] +enum MyEnum { + UnitWithExplicitDiscriminant = 0, + EmptyStructSingleLineBlockComment {/* Comment */} = 1, + EmptyStructMultiLineBlockComment { + /* + * Comment + */ + } = 2, + EmptyStructLineComment { + // comment + } = 3, + EmptyTupleSingleLineBlockComment(/* Comment */) = 4, + EmptyTupleMultiLineBlockComment( + /* + * Comment + */ + ) = 5, + EmptyTupleLineComment( + // comment + ) = 6, +} + +enum Animal { + Dog(/* tuple variant closer in comment -> ) */) = 1, + #[hello(world)] + Cat(/* tuple variant close in leading attribute */) = 2, + Bee( + /* tuple variant closer on associated field attribute */ #[hello(world)] usize, + ) = 3, + Fox(/* tuple variant closer on const fn call */) = some_const_fn(), + Ant(/* tuple variant closer on macro call */) = some_macro!(), + Snake {/* stuct variant closer in comment -> } */} = 6, + #[hell{world}] + Cobra {/* struct variant close in leading attribute */} = 6, + Eagle { + /* struct variant closer on associated field attribute */ + #[hell{world}] + value: Sting, + } = 7, + Koala {/* struct variant closer on macro call */} = some_macro! {}, +} diff --git a/src/tools/rustfmt/tests/target/issue_5691.rs b/src/tools/rustfmt/tests/target/issue_5691.rs new file mode 100644 index 00000000000..e3aad15db0d --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_5691.rs @@ -0,0 +1,16 @@ +struct S<const C: usize> +where + [(); { num_slots!(C) }]:, { + /* An asterisk-based, or a double-slash-prefixed, comment here is + required to trigger the fmt bug. + + A single-line triple-slash-prefixed comment (with a field following it) is not enough - it will not trigger the fmt bug. + + Side note: If you have a combination of two, or all three of the + above mentioned types of comments here, some of them disappear + after `cargo fmt`. + + The bug gets triggered even if a field definition following the + (asterisk-based, or a double-slash-prefixed) comment, too. + */ +} diff --git a/src/tools/rustfmt/tests/target/issue_5728.rs b/src/tools/rustfmt/tests/target/issue_5728.rs new file mode 100644 index 00000000000..e1355416faf --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_5728.rs @@ -0,0 +1,5 @@ +cfg_if::cfg_if! { + if #[cfg(windows)] { + } else if #(&cpus) { + } else [libc::CTL_HW, libc::HW_NCPU, 0, 0] +} diff --git a/src/tools/rustfmt/tests/target/issue_5729.rs b/src/tools/rustfmt/tests/target/issue_5729.rs new file mode 100644 index 00000000000..d63c83e88f8 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_5729.rs @@ -0,0 +1,5 @@ +cfg_if::cfg_if! { + if { + } else if #(&cpus) { + } else [libc::CTL_HW, libc::HW_NCPU, 0, 0] +} diff --git a/src/tools/rustfmt/tests/target/itemized-blocks/no_wrap.rs b/src/tools/rustfmt/tests/target/itemized-blocks/no_wrap.rs index de885638272..86818b44745 100644 --- a/src/tools/rustfmt/tests/target/itemized-blocks/no_wrap.rs +++ b/src/tools/rustfmt/tests/target/itemized-blocks/no_wrap.rs @@ -1,7 +1,7 @@ // rustfmt-normalize_comments: true // rustfmt-format_code_in_doc_comments: true -//! This is a list: +//! This is an itemized markdown list (see also issue #3224): //! * Outer //! * Outer //! * Inner @@ -13,6 +13,40 @@ //! - when the log level is info, the level name is green and the rest of the line is white //! - when the log level is debug, the whole line is white //! - when the log level is trace, the whole line is gray ("bright black") +//! +//! This is a numbered markdown list (see also issue #5416): +//! 1. Long long long long long long long long long long long long long long long long long line +//! 2. Another very long long long long long long long long long long long long long long long line +//! 3. Nested list +//! 1. Long long long long long long long long long long long long long long long long line +//! 2. Another very long long long long long long long long long long long long long long line +//! 4. Last item +//! +//! Using the ')' instead of '.' character after the number: +//! 1) Long long long long long long long long long long long long long long long long long line +//! 2) Another very long long long long long long long long long long long long long long long line +//! +//! Deep list that mixes various bullet and number formats: +//! 1. First level with a long long long long long long long long long long long long long long +//! long long long line +//! 2. First level with another very long long long long long long long long long long long long +//! long long long line +//! * Second level with a long long long long long long long long long long long long long +//! long long long line +//! * Second level with another very long long long long long long long long long long long +//! long long long line +//! 1) Third level with a long long long long long long long long long long long long long +//! long long long line +//! 2) Third level with another very long long long long long long long long long long +//! long long long long line +//! - Forth level with a long long long long long long long long long long long long +//! long long long long line +//! - Forth level with another very long long long long long long long long long long +//! long long long long line +//! 3) One more item at the third level +//! 4) Last item of the third level +//! * Last item of second level +//! 3. Last item of first level /// All the parameters ***except for `from_theater`*** should be inserted as sent by the remote /// theater, i.e., as passed to [`Theater::send`] on the remote actor: diff --git a/src/tools/rustfmt/tests/target/itemized-blocks/wrap.rs b/src/tools/rustfmt/tests/target/itemized-blocks/wrap.rs index a4907303c9e..4826590ea59 100644 --- a/src/tools/rustfmt/tests/target/itemized-blocks/wrap.rs +++ b/src/tools/rustfmt/tests/target/itemized-blocks/wrap.rs @@ -2,7 +2,8 @@ // rustfmt-format_code_in_doc_comments: true // rustfmt-max_width: 50 -//! This is a list: +//! This is an itemized markdown list (see also +//! issue #3224): //! * Outer //! * Outer //! * Inner @@ -23,6 +24,65 @@ //! is white //! - when the log level is trace, the whole line //! is gray ("bright black") +//! +//! This is a numbered markdown list (see also +//! issue #5416): +//! 1. Long long long long long long long long +//! long long long long long long long long +//! long line +//! 2. Another very long long long long long long +//! long long long long long long long long +//! long line +//! 3. Nested list +//! 1. Long long long long long long long long +//! long long long long long long long long +//! line +//! 2. Another very long long long long long +//! long long long long long long long long +//! long line +//! 4. Last item +//! +//! Using the ')' instead of '.' character after +//! the number: +//! 1) Long long long long long long long long +//! long long long long long long long long +//! long line +//! 2) Another very long long long long long long +//! long long long long long long long long +//! long line +//! +//! Deep list that mixes various bullet and number +//! formats: +//! 1. First level with a long long long long long +//! long long long long long long long long +//! long long long long line +//! 2. First level with another very long long +//! long long long long long long long long +//! long long long long long line +//! * Second level with a long long long long +//! long long long long long long long long +//! long long long long line +//! * Second level with another very long long +//! long long long long long long long long +//! long long long long line +//! 1) Third level with a long long long +//! long long long long long long long +//! long long long long long long line +//! 2) Third level with another very long +//! long long long long long long long +//! long long long long long long line +//! - Forth level with a long long +//! long long long long long long +//! long long long long long long +//! long long line +//! - Forth level with another very +//! long long long long long long +//! long long long long long long +//! long long line +//! 3) One more item at the third level +//! 4) Last item of the third level +//! * Last item of second level +//! 3. Last item of first level // This example shows how to configure fern to // output really nicely colored logs diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 0bc50c64133..8db479af286 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -16,9 +16,6 @@ const LICENSES: &[&str] = &[ "Apache-2.0 OR MIT", "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT", // wasi license "Apache-2.0/MIT", - "BSD-2-Clause", // arrayref from Cargo - "CC0-1.0 OR Apache-2.0", // blake3 from Cargo - "CC0-1.0 OR MIT-0 OR Apache-2.0", // constant_time_eq from cargo "ISC", "MIT / Apache-2.0", "MIT OR Apache-2.0 OR Zlib", // tinyvec_macros diff --git a/tests/codegen/naked-nocoverage.rs b/tests/codegen/naked-nocoverage.rs index 91a6260bf2a..3c755e49c6d 100644 --- a/tests/codegen/naked-nocoverage.rs +++ b/tests/codegen/naked-nocoverage.rs @@ -11,7 +11,7 @@ use std::arch::asm; #[naked] #[no_mangle] pub unsafe extern "C" fn f() { - // CHECK: define void @f() + // CHECK: define {{(dso_local )?}}void @f() // CHECK-NEXT: start: // CHECK-NEXT: call void asm // CHECK-NEXT: unreachable diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs b/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs index 472d921ace0..63e63c5d4aa 100644 --- a/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs +++ b/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs @@ -61,7 +61,19 @@ pub type Type9 = impl Send; pub type Type10 = impl Send; pub type Type11 = impl Send; -pub fn fn1<'a>() { +pub fn fn1<'a>() where + Type1: 'static, + Type2: 'static, + Type3: 'static, + Type4: 'static, + Type5: 'static, + Type6: 'static, + Type7: 'static, + Type8: 'static, + Type9: 'static, + Type10: 'static, + Type11: 'static, +{ // Closure let closure1 = || { }; let _: Type1 = closure1; diff --git a/tests/codegen/stack-protector.rs b/tests/codegen/stack-protector.rs index a24e6f1e4f1..a680789af15 100644 --- a/tests/codegen/stack-protector.rs +++ b/tests/codegen/stack-protector.rs @@ -10,25 +10,25 @@ pub fn foo() { // CHECK: @foo() unnamed_addr #0 - // all-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} } - // all-NOT: attributes #0 = { {{.*}} ssp {{.*}} } - // all: attributes #0 = { {{.*}} sspreq {{.*}} } - // all-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} } - // all-NOT: attributes #0 = { {{.*}} ssp {{.*}} } + // all-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } + // all-NOT: attributes #0 = { {{.*}}ssp {{.*}} } + // all: attributes #0 = { {{.*}}sspreq {{.*}} } + // all-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } + // all-NOT: attributes #0 = { {{.*}}ssp {{.*}} } - // strong-NOT: attributes #0 = { {{.*}} sspreq {{.*}} } - // strong-NOT: attributes #0 = { {{.*}} ssp {{.*}} } - // strong: attributes #0 = { {{.*}} sspstrong {{.*}} } - // strong-NOT: attributes #0 = { {{.*}} sspreq {{.*}} } - // strong-NOT: attributes #0 = { {{.*}} ssp {{.*}} } + // strong-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } + // strong-NOT: attributes #0 = { {{.*}}ssp {{.*}} } + // strong: attributes #0 = { {{.*}}sspstrong {{.*}} } + // strong-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } + // strong-NOT: attributes #0 = { {{.*}}ssp {{.*}} } - // basic-NOT: attributes #0 = { {{.*}} sspreq {{.*}} } - // basic-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} } - // basic: attributes #0 = { {{.*}} ssp {{.*}} } - // basic-NOT: attributes #0 = { {{.*}} sspreq {{.*}} } - // basic-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} } + // basic-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } + // basic-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } + // basic: attributes #0 = { {{.*}}ssp {{.*}} } + // basic-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } + // basic-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } - // none-NOT: attributes #0 = { {{.*}} sspreq {{.*}} } - // none-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} } - // none-NOT: attributes #0 = { {{.*}} ssp {{.*}} } + // none-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } + // none-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } + // none-NOT: attributes #0 = { {{.*}}ssp {{.*}} } } diff --git a/tests/codegen/unchecked_shifts.rs b/tests/codegen/unchecked_shifts.rs index 60d0cb09aca..0924dda08ee 100644 --- a/tests/codegen/unchecked_shifts.rs +++ b/tests/codegen/unchecked_shifts.rs @@ -8,6 +8,7 @@ // CHECK-LABEL: @unchecked_shl_unsigned_same #[no_mangle] pub unsafe fn unchecked_shl_unsigned_same(a: u32, b: u32) -> u32 { + // CHECK-NOT: assume // CHECK-NOT: and i32 // CHECK: shl i32 %a, %b // CHECK-NOT: and i32 @@ -30,6 +31,7 @@ pub unsafe fn unchecked_shl_unsigned_smaller(a: u16, b: u32) -> u16 { // CHECK-LABEL: @unchecked_shl_unsigned_bigger #[no_mangle] pub unsafe fn unchecked_shl_unsigned_bigger(a: u64, b: u32) -> u64 { + // CHECK-NOT: assume // CHECK: %[[EXT:.+]] = zext i32 %b to i64 // CHECK: shl i64 %a, %[[EXT]] a.unchecked_shl(b) @@ -38,6 +40,7 @@ pub unsafe fn unchecked_shl_unsigned_bigger(a: u64, b: u32) -> u64 { // CHECK-LABEL: @unchecked_shr_signed_same #[no_mangle] pub unsafe fn unchecked_shr_signed_same(a: i32, b: u32) -> i32 { + // CHECK-NOT: assume // CHECK-NOT: and i32 // CHECK: ashr i32 %a, %b // CHECK-NOT: and i32 @@ -60,6 +63,7 @@ pub unsafe fn unchecked_shr_signed_smaller(a: i16, b: u32) -> i16 { // CHECK-LABEL: @unchecked_shr_signed_bigger #[no_mangle] pub unsafe fn unchecked_shr_signed_bigger(a: i64, b: u32) -> i64 { + // CHECK-NOT: assume // CHECK: %[[EXT:.+]] = zext i32 %b to i64 // CHECK: ashr i64 %a, %[[EXT]] a.unchecked_shr(b) diff --git a/tests/mir-opt/const_goto_const_eval_fail.rs b/tests/mir-opt/const_goto_const_eval_fail.rs index 3b85fe6ab3c..b2357663a90 100644 --- a/tests/mir-opt/const_goto_const_eval_fail.rs +++ b/tests/mir-opt/const_goto_const_eval_fail.rs @@ -1,6 +1,8 @@ #![feature(min_const_generics)] #![crate_type = "lib"] +// compile-flags: -Zunsound-mir-opts + // If const eval fails, then don't crash // EMIT_MIR const_goto_const_eval_fail.f.ConstGoto.diff pub fn f<const A: i32, const B: bool>() -> u64 { diff --git a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.diff b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.diff deleted file mode 100644 index b510cecd9e0..00000000000 --- a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.diff +++ /dev/null @@ -1,44 +0,0 @@ -- // MIR for `concrete` before ConstProp -+ // MIR for `concrete` after ConstProp - - fn concrete() -> () { - let mut _0: (); - let _1: usize; - scope 1 { - debug x => _1; - let _2: usize; - scope 2 { - debug y => _2; - let _3: usize; - scope 3 { - debug z0 => _3; - let _4: usize; - scope 4 { - debug z1 => _4; - } - } - } - } - - bb0: { - StorageLive(_1); -- _1 = OffsetOf(Alpha, [0]); -+ _1 = const 4_usize; - StorageLive(_2); -- _2 = OffsetOf(Alpha, [1]); -+ _2 = const 0_usize; - StorageLive(_3); -- _3 = OffsetOf(Alpha, [2, 0]); -+ _3 = const 2_usize; - StorageLive(_4); -- _4 = OffsetOf(Alpha, [2, 1]); -+ _4 = const 3_usize; - _0 = const (); - StorageDead(_4); - StorageDead(_3); - StorageDead(_2); - StorageDead(_1); - return; - } - } - diff --git a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-abort.diff new file mode 100644 index 00000000000..046a79b4bfb --- /dev/null +++ b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-abort.diff @@ -0,0 +1,72 @@ +- // MIR for `concrete` before ConstProp ++ // MIR for `concrete` after ConstProp + + fn concrete() -> () { + let mut _0: (); + let _1: usize; + let mut _2: usize; + let mut _4: usize; + let mut _6: usize; + let mut _8: usize; + scope 1 { + debug x => _1; + let _3: usize; + scope 2 { + debug y => _3; + let _5: usize; + scope 3 { + debug z0 => _5; + let _7: usize; + scope 4 { + debug z1 => _7; + } + } + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); +- _2 = OffsetOf(Alpha, [0]); ++ _2 = const 4_usize; + _1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_2); + StorageLive(_3); + StorageLive(_4); +- _4 = OffsetOf(Alpha, [1]); ++ _4 = const 0_usize; + _3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable]; + } + + bb2: { + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); +- _6 = OffsetOf(Alpha, [2, 0]); ++ _6 = const 2_usize; + _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable]; + } + + bb3: { + StorageDead(_6); + StorageLive(_7); + StorageLive(_8); +- _8 = OffsetOf(Alpha, [2, 1]); ++ _8 = const 3_usize; + _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable]; + } + + bb4: { + StorageDead(_8); + _0 = const (); + StorageDead(_7); + StorageDead(_5); + StorageDead(_3); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff new file mode 100644 index 00000000000..29cad611b54 --- /dev/null +++ b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff @@ -0,0 +1,72 @@ +- // MIR for `concrete` before ConstProp ++ // MIR for `concrete` after ConstProp + + fn concrete() -> () { + let mut _0: (); + let _1: usize; + let mut _2: usize; + let mut _4: usize; + let mut _6: usize; + let mut _8: usize; + scope 1 { + debug x => _1; + let _3: usize; + scope 2 { + debug y => _3; + let _5: usize; + scope 3 { + debug z0 => _5; + let _7: usize; + scope 4 { + debug z1 => _7; + } + } + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); +- _2 = OffsetOf(Alpha, [0]); ++ _2 = const 4_usize; + _1 = must_use::<usize>(move _2) -> bb1; + } + + bb1: { + StorageDead(_2); + StorageLive(_3); + StorageLive(_4); +- _4 = OffsetOf(Alpha, [1]); ++ _4 = const 0_usize; + _3 = must_use::<usize>(move _4) -> bb2; + } + + bb2: { + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); +- _6 = OffsetOf(Alpha, [2, 0]); ++ _6 = const 2_usize; + _5 = must_use::<usize>(move _6) -> bb3; + } + + bb3: { + StorageDead(_6); + StorageLive(_7); + StorageLive(_8); +- _8 = OffsetOf(Alpha, [2, 1]); ++ _8 = const 3_usize; + _7 = must_use::<usize>(move _8) -> bb4; + } + + bb4: { + StorageDead(_8); + _0 = const (); + StorageDead(_7); + StorageDead(_5); + StorageDead(_3); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.diff b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.diff deleted file mode 100644 index 8e0adb42755..00000000000 --- a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.diff +++ /dev/null @@ -1,40 +0,0 @@ -- // MIR for `generic` before ConstProp -+ // MIR for `generic` after ConstProp - - fn generic() -> () { - let mut _0: (); - let _1: usize; - scope 1 { - debug gx => _1; - let _2: usize; - scope 2 { - debug gy => _2; - let _3: usize; - scope 3 { - debug dx => _3; - let _4: usize; - scope 4 { - debug dy => _4; - } - } - } - } - - bb0: { - StorageLive(_1); - _1 = OffsetOf(Gamma<T>, [0]); - StorageLive(_2); - _2 = OffsetOf(Gamma<T>, [1]); - StorageLive(_3); - _3 = OffsetOf(Delta<T>, [1]); - StorageLive(_4); - _4 = OffsetOf(Delta<T>, [2]); - _0 = const (); - StorageDead(_4); - StorageDead(_3); - StorageDead(_2); - StorageDead(_1); - return; - } - } - diff --git a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-abort.diff new file mode 100644 index 00000000000..7519331f6d7 --- /dev/null +++ b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-abort.diff @@ -0,0 +1,68 @@ +- // MIR for `generic` before ConstProp ++ // MIR for `generic` after ConstProp + + fn generic() -> () { + let mut _0: (); + let _1: usize; + let mut _2: usize; + let mut _4: usize; + let mut _6: usize; + let mut _8: usize; + scope 1 { + debug gx => _1; + let _3: usize; + scope 2 { + debug gy => _3; + let _5: usize; + scope 3 { + debug dx => _5; + let _7: usize; + scope 4 { + debug dy => _7; + } + } + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = OffsetOf(Gamma<T>, [0]); + _1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_2); + StorageLive(_3); + StorageLive(_4); + _4 = OffsetOf(Gamma<T>, [1]); + _3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable]; + } + + bb2: { + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); + _6 = OffsetOf(Delta<T>, [1]); + _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable]; + } + + bb3: { + StorageDead(_6); + StorageLive(_7); + StorageLive(_8); + _8 = OffsetOf(Delta<T>, [2]); + _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable]; + } + + bb4: { + StorageDead(_8); + _0 = const (); + StorageDead(_7); + StorageDead(_5); + StorageDead(_3); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff new file mode 100644 index 00000000000..2a58a1a5ceb --- /dev/null +++ b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff @@ -0,0 +1,68 @@ +- // MIR for `generic` before ConstProp ++ // MIR for `generic` after ConstProp + + fn generic() -> () { + let mut _0: (); + let _1: usize; + let mut _2: usize; + let mut _4: usize; + let mut _6: usize; + let mut _8: usize; + scope 1 { + debug gx => _1; + let _3: usize; + scope 2 { + debug gy => _3; + let _5: usize; + scope 3 { + debug dx => _5; + let _7: usize; + scope 4 { + debug dy => _7; + } + } + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = OffsetOf(Gamma<T>, [0]); + _1 = must_use::<usize>(move _2) -> bb1; + } + + bb1: { + StorageDead(_2); + StorageLive(_3); + StorageLive(_4); + _4 = OffsetOf(Gamma<T>, [1]); + _3 = must_use::<usize>(move _4) -> bb2; + } + + bb2: { + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); + _6 = OffsetOf(Delta<T>, [1]); + _5 = must_use::<usize>(move _6) -> bb3; + } + + bb3: { + StorageDead(_6); + StorageLive(_7); + StorageLive(_8); + _8 = OffsetOf(Delta<T>, [2]); + _7 = must_use::<usize>(move _8) -> bb4; + } + + bb4: { + StorageDead(_8); + _0 = const (); + StorageDead(_7); + StorageDead(_5); + StorageDead(_3); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/const_prop/offset_of.rs b/tests/mir-opt/const_prop/offset_of.rs index 4cdcd28eeb2..164db59572b 100644 --- a/tests/mir-opt/const_prop/offset_of.rs +++ b/tests/mir-opt/const_prop/offset_of.rs @@ -1,4 +1,5 @@ // unit-test: ConstProp +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY #![feature(offset_of)] diff --git a/tests/mir-opt/inline/unchecked_shifts.rs b/tests/mir-opt/inline/unchecked_shifts.rs index 64ec26b587d..22f84e44a64 100644 --- a/tests/mir-opt/inline/unchecked_shifts.rs +++ b/tests/mir-opt/inline/unchecked_shifts.rs @@ -16,3 +16,15 @@ pub unsafe fn unchecked_shl_unsigned_smaller(a: u16, b: u32) -> u16 { pub unsafe fn unchecked_shr_signed_smaller(a: i16, b: u32) -> i16 { a.unchecked_shr(b) } + +// EMIT_MIR unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.diff +// EMIT_MIR unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.mir +pub unsafe fn unchecked_shl_unsigned_bigger(a: u64, b: u32) -> u64 { + a.unchecked_shl(b) +} + +// EMIT_MIR unchecked_shifts.unchecked_shr_signed_bigger.Inline.diff +// EMIT_MIR unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.mir +pub unsafe fn unchecked_shr_signed_bigger(a: i64, b: u32) -> i64 { + a.unchecked_shr(b) +} diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-abort.diff new file mode 100644 index 00000000000..1ab1d01e5fa --- /dev/null +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-abort.diff @@ -0,0 +1,36 @@ +- // MIR for `unchecked_shl_unsigned_bigger` before Inline ++ // MIR for `unchecked_shl_unsigned_bigger` after Inline + + fn unchecked_shl_unsigned_bigger(_1: u64, _2: u32) -> u64 { + debug a => _1; + debug b => _2; + let mut _0: u64; + let mut _3: u64; + let mut _4: u32; ++ scope 1 (inlined core::num::<impl u64>::unchecked_shl) { ++ debug self => _3; ++ debug rhs => _4; ++ let mut _5: u64; ++ scope 2 { ++ } ++ } + + bb0: { + StorageLive(_3); + _3 = _1; + StorageLive(_4); + _4 = _2; +- _0 = core::num::<impl u64>::unchecked_shl(move _3, move _4) -> [return: bb1, unwind unreachable]; +- } +- +- bb1: { ++ StorageLive(_5); ++ _5 = _4 as u64 (IntToInt); ++ _0 = ShlUnchecked(_3, move _5); ++ StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-unwind.diff new file mode 100644 index 00000000000..577fc8bee66 --- /dev/null +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-unwind.diff @@ -0,0 +1,36 @@ +- // MIR for `unchecked_shl_unsigned_bigger` before Inline ++ // MIR for `unchecked_shl_unsigned_bigger` after Inline + + fn unchecked_shl_unsigned_bigger(_1: u64, _2: u32) -> u64 { + debug a => _1; + debug b => _2; + let mut _0: u64; + let mut _3: u64; + let mut _4: u32; ++ scope 1 (inlined core::num::<impl u64>::unchecked_shl) { ++ debug self => _3; ++ debug rhs => _4; ++ let mut _5: u64; ++ scope 2 { ++ } ++ } + + bb0: { + StorageLive(_3); + _3 = _1; + StorageLive(_4); + _4 = _2; +- _0 = core::num::<impl u64>::unchecked_shl(move _3, move _4) -> bb1; +- } +- +- bb1: { ++ StorageLive(_5); ++ _5 = _4 as u64 (IntToInt); ++ _0 = ShlUnchecked(_3, move _5); ++ StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-abort.mir new file mode 100644 index 00000000000..65b832497f9 --- /dev/null +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-abort.mir @@ -0,0 +1,22 @@ +// MIR for `unchecked_shl_unsigned_bigger` after PreCodegen + +fn unchecked_shl_unsigned_bigger(_1: u64, _2: u32) -> u64 { + debug a => _1; + debug b => _2; + let mut _0: u64; + scope 1 (inlined core::num::<impl u64>::unchecked_shl) { + debug self => _1; + debug rhs => _2; + let mut _3: u64; + scope 2 { + } + } + + bb0: { + StorageLive(_3); + _3 = _2 as u64 (IntToInt); + _0 = ShlUnchecked(_1, move _3); + StorageDead(_3); + return; + } +} diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-unwind.mir new file mode 100644 index 00000000000..65b832497f9 --- /dev/null +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-unwind.mir @@ -0,0 +1,22 @@ +// MIR for `unchecked_shl_unsigned_bigger` after PreCodegen + +fn unchecked_shl_unsigned_bigger(_1: u64, _2: u32) -> u64 { + debug a => _1; + debug b => _2; + let mut _0: u64; + scope 1 (inlined core::num::<impl u64>::unchecked_shl) { + debug self => _1; + debug rhs => _2; + let mut _3: u64; + scope 2 { + } + } + + bb0: { + StorageLive(_3); + _3 = _2 as u64 (IntToInt); + _0 = ShlUnchecked(_1, move _3); + StorageDead(_3); + return; + } +} diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff index 093925b8e4f..90b32247c95 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff @@ -7,16 +7,36 @@ let mut _0: u16; let mut _3: u16; let mut _4: u32; ++ scope 1 (inlined core::num::<impl u16>::unchecked_shl) { ++ debug self => _3; ++ debug rhs => _4; ++ let mut _5: u16; ++ let mut _6: bool; ++ let mut _7: u32; ++ scope 2 { ++ } ++ } bb0: { StorageLive(_3); _3 = _1; StorageLive(_4); _4 = _2; - _0 = core::num::<impl u16>::unchecked_shl(move _3, move _4) -> [return: bb1, unwind unreachable]; - } - - bb1: { +- _0 = core::num::<impl u16>::unchecked_shl(move _3, move _4) -> [return: bb1, unwind unreachable]; +- } +- +- bb1: { ++ StorageLive(_5); ++ StorageLive(_6); ++ StorageLive(_7); ++ _7 = const 65535_u32; ++ _6 = Le(_4, move _7); ++ StorageDead(_7); ++ assume(move _6); ++ StorageDead(_6); ++ _5 = _4 as u16 (IntToInt); ++ _0 = ShlUnchecked(_3, move _5); ++ StorageDead(_5); StorageDead(_4); StorageDead(_3); return; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff index 50934e0439a..ba159c063b3 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff @@ -7,16 +7,36 @@ let mut _0: u16; let mut _3: u16; let mut _4: u32; ++ scope 1 (inlined core::num::<impl u16>::unchecked_shl) { ++ debug self => _3; ++ debug rhs => _4; ++ let mut _5: u16; ++ let mut _6: bool; ++ let mut _7: u32; ++ scope 2 { ++ } ++ } bb0: { StorageLive(_3); _3 = _1; StorageLive(_4); _4 = _2; - _0 = core::num::<impl u16>::unchecked_shl(move _3, move _4) -> bb1; - } - - bb1: { +- _0 = core::num::<impl u16>::unchecked_shl(move _3, move _4) -> bb1; +- } +- +- bb1: { ++ StorageLive(_5); ++ StorageLive(_6); ++ StorageLive(_7); ++ _7 = const 65535_u32; ++ _6 = Le(_4, move _7); ++ StorageDead(_7); ++ assume(move _6); ++ StorageDead(_6); ++ _5 = _4 as u16 (IntToInt); ++ _0 = ShlUnchecked(_3, move _5); ++ StorageDead(_5); StorageDead(_4); StorageDead(_3); return; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir index 46f3511b14c..3f388a69d7e 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir @@ -4,12 +4,28 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 { debug a => _1; debug b => _2; let mut _0: u16; - - bb0: { - _0 = core::num::<impl u16>::unchecked_shl(_1, _2) -> [return: bb1, unwind unreachable]; + scope 1 (inlined core::num::<impl u16>::unchecked_shl) { + debug self => _1; + debug rhs => _2; + let mut _3: u32; + let mut _4: bool; + let mut _5: u16; + scope 2 { + } } - bb1: { + bb0: { + StorageLive(_5); + StorageLive(_4); + StorageLive(_3); + _3 = const 65535_u32; + _4 = Le(_2, move _3); + StorageDead(_3); + assume(move _4); + StorageDead(_4); + _5 = _2 as u16 (IntToInt); + _0 = ShlUnchecked(_1, move _5); + StorageDead(_5); return; } } diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir index 35fee449c35..3f388a69d7e 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir @@ -4,12 +4,28 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 { debug a => _1; debug b => _2; let mut _0: u16; - - bb0: { - _0 = core::num::<impl u16>::unchecked_shl(_1, _2) -> bb1; + scope 1 (inlined core::num::<impl u16>::unchecked_shl) { + debug self => _1; + debug rhs => _2; + let mut _3: u32; + let mut _4: bool; + let mut _5: u16; + scope 2 { + } } - bb1: { + bb0: { + StorageLive(_5); + StorageLive(_4); + StorageLive(_3); + _3 = const 65535_u32; + _4 = Le(_2, move _3); + StorageDead(_3); + assume(move _4); + StorageDead(_4); + _5 = _2 as u16 (IntToInt); + _0 = ShlUnchecked(_1, move _5); + StorageDead(_5); return; } } diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff new file mode 100644 index 00000000000..1e83fec4f3d --- /dev/null +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff @@ -0,0 +1,36 @@ +- // MIR for `unchecked_shr_signed_bigger` before Inline ++ // MIR for `unchecked_shr_signed_bigger` after Inline + + fn unchecked_shr_signed_bigger(_1: i64, _2: u32) -> i64 { + debug a => _1; + debug b => _2; + let mut _0: i64; + let mut _3: i64; + let mut _4: u32; ++ scope 1 (inlined core::num::<impl i64>::unchecked_shr) { ++ debug self => _3; ++ debug rhs => _4; ++ let mut _5: i64; ++ scope 2 { ++ } ++ } + + bb0: { + StorageLive(_3); + _3 = _1; + StorageLive(_4); + _4 = _2; +- _0 = core::num::<impl i64>::unchecked_shr(move _3, move _4) -> [return: bb1, unwind unreachable]; +- } +- +- bb1: { ++ StorageLive(_5); ++ _5 = _4 as i64 (IntToInt); ++ _0 = ShrUnchecked(_3, move _5); ++ StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff new file mode 100644 index 00000000000..d7ff104b92e --- /dev/null +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff @@ -0,0 +1,36 @@ +- // MIR for `unchecked_shr_signed_bigger` before Inline ++ // MIR for `unchecked_shr_signed_bigger` after Inline + + fn unchecked_shr_signed_bigger(_1: i64, _2: u32) -> i64 { + debug a => _1; + debug b => _2; + let mut _0: i64; + let mut _3: i64; + let mut _4: u32; ++ scope 1 (inlined core::num::<impl i64>::unchecked_shr) { ++ debug self => _3; ++ debug rhs => _4; ++ let mut _5: i64; ++ scope 2 { ++ } ++ } + + bb0: { + StorageLive(_3); + _3 = _1; + StorageLive(_4); + _4 = _2; +- _0 = core::num::<impl i64>::unchecked_shr(move _3, move _4) -> bb1; +- } +- +- bb1: { ++ StorageLive(_5); ++ _5 = _4 as i64 (IntToInt); ++ _0 = ShrUnchecked(_3, move _5); ++ StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir new file mode 100644 index 00000000000..7524ec4970e --- /dev/null +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir @@ -0,0 +1,22 @@ +// MIR for `unchecked_shr_signed_bigger` after PreCodegen + +fn unchecked_shr_signed_bigger(_1: i64, _2: u32) -> i64 { + debug a => _1; + debug b => _2; + let mut _0: i64; + scope 1 (inlined core::num::<impl i64>::unchecked_shr) { + debug self => _1; + debug rhs => _2; + let mut _3: i64; + scope 2 { + } + } + + bb0: { + StorageLive(_3); + _3 = _2 as i64 (IntToInt); + _0 = ShrUnchecked(_1, move _3); + StorageDead(_3); + return; + } +} diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir new file mode 100644 index 00000000000..7524ec4970e --- /dev/null +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir @@ -0,0 +1,22 @@ +// MIR for `unchecked_shr_signed_bigger` after PreCodegen + +fn unchecked_shr_signed_bigger(_1: i64, _2: u32) -> i64 { + debug a => _1; + debug b => _2; + let mut _0: i64; + scope 1 (inlined core::num::<impl i64>::unchecked_shr) { + debug self => _1; + debug rhs => _2; + let mut _3: i64; + scope 2 { + } + } + + bb0: { + StorageLive(_3); + _3 = _2 as i64 (IntToInt); + _0 = ShrUnchecked(_1, move _3); + StorageDead(_3); + return; + } +} diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-abort.diff index 1659a51b090..fa7e5d16e39 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-abort.diff @@ -7,16 +7,36 @@ let mut _0: i16; let mut _3: i16; let mut _4: u32; ++ scope 1 (inlined core::num::<impl i16>::unchecked_shr) { ++ debug self => _3; ++ debug rhs => _4; ++ let mut _5: i16; ++ let mut _6: bool; ++ let mut _7: u32; ++ scope 2 { ++ } ++ } bb0: { StorageLive(_3); _3 = _1; StorageLive(_4); _4 = _2; - _0 = core::num::<impl i16>::unchecked_shr(move _3, move _4) -> [return: bb1, unwind unreachable]; - } - - bb1: { +- _0 = core::num::<impl i16>::unchecked_shr(move _3, move _4) -> [return: bb1, unwind unreachable]; +- } +- +- bb1: { ++ StorageLive(_5); ++ StorageLive(_6); ++ StorageLive(_7); ++ _7 = const 32767_u32; ++ _6 = Le(_4, move _7); ++ StorageDead(_7); ++ assume(move _6); ++ StorageDead(_6); ++ _5 = _4 as i16 (IntToInt); ++ _0 = ShrUnchecked(_3, move _5); ++ StorageDead(_5); StorageDead(_4); StorageDead(_3); return; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-unwind.diff index cb5ec37feb3..3d398e00fc8 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-unwind.diff @@ -7,16 +7,36 @@ let mut _0: i16; let mut _3: i16; let mut _4: u32; ++ scope 1 (inlined core::num::<impl i16>::unchecked_shr) { ++ debug self => _3; ++ debug rhs => _4; ++ let mut _5: i16; ++ let mut _6: bool; ++ let mut _7: u32; ++ scope 2 { ++ } ++ } bb0: { StorageLive(_3); _3 = _1; StorageLive(_4); _4 = _2; - _0 = core::num::<impl i16>::unchecked_shr(move _3, move _4) -> bb1; - } - - bb1: { +- _0 = core::num::<impl i16>::unchecked_shr(move _3, move _4) -> bb1; +- } +- +- bb1: { ++ StorageLive(_5); ++ StorageLive(_6); ++ StorageLive(_7); ++ _7 = const 32767_u32; ++ _6 = Le(_4, move _7); ++ StorageDead(_7); ++ assume(move _6); ++ StorageDead(_6); ++ _5 = _4 as i16 (IntToInt); ++ _0 = ShrUnchecked(_3, move _5); ++ StorageDead(_5); StorageDead(_4); StorageDead(_3); return; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-abort.mir index 9f2f40002a3..64ea25349ac 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-abort.mir @@ -4,12 +4,28 @@ fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 { debug a => _1; debug b => _2; let mut _0: i16; - - bb0: { - _0 = core::num::<impl i16>::unchecked_shr(_1, _2) -> [return: bb1, unwind unreachable]; + scope 1 (inlined core::num::<impl i16>::unchecked_shr) { + debug self => _1; + debug rhs => _2; + let mut _3: u32; + let mut _4: bool; + let mut _5: i16; + scope 2 { + } } - bb1: { + bb0: { + StorageLive(_5); + StorageLive(_4); + StorageLive(_3); + _3 = const 32767_u32; + _4 = Le(_2, move _3); + StorageDead(_3); + assume(move _4); + StorageDead(_4); + _5 = _2 as i16 (IntToInt); + _0 = ShrUnchecked(_1, move _5); + StorageDead(_5); return; } } diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-unwind.mir index aaf3bb62e8a..64ea25349ac 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-unwind.mir @@ -4,12 +4,28 @@ fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 { debug a => _1; debug b => _2; let mut _0: i16; - - bb0: { - _0 = core::num::<impl i16>::unchecked_shr(_1, _2) -> bb1; + scope 1 (inlined core::num::<impl i16>::unchecked_shr) { + debug self => _1; + debug rhs => _2; + let mut _3: u32; + let mut _4: bool; + let mut _5: i16; + scope 2 { + } } - bb1: { + bb0: { + StorageLive(_5); + StorageLive(_4); + StorageLive(_3); + _3 = const 32767_u32; + _4 = Le(_2, move _3); + StorageDead(_3); + assume(move _4); + StorageDead(_4); + _5 = _2 as i16 (IntToInt); + _0 = ShrUnchecked(_1, move _5); + StorageDead(_5); return; } } diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs index 876b4497034..0758e9b775b 100644 --- a/tests/mir-opt/lower_intrinsics.rs +++ b/tests/mir-opt/lower_intrinsics.rs @@ -13,8 +13,13 @@ pub fn wrapping(a: i32, b: i32) { // EMIT_MIR lower_intrinsics.unchecked.LowerIntrinsics.diff pub unsafe fn unchecked(a: i32, b: i32) { + let _a = core::intrinsics::unchecked_add(a, b); + let _b = core::intrinsics::unchecked_sub(a, b); + let _c = core::intrinsics::unchecked_mul(a, b); let _x = core::intrinsics::unchecked_div(a, b); let _y = core::intrinsics::unchecked_rem(a, b); + let _i = core::intrinsics::unchecked_shl(a, b); + let _j = core::intrinsics::unchecked_shr(a, b); } // EMIT_MIR lower_intrinsics.size_of.LowerIntrinsics.diff diff --git a/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-abort.diff index c532d74ced0..dd92b8d6d2c 100644 --- a/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-abort.diff +++ b/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-abort.diff @@ -10,11 +10,41 @@ let mut _5: i32; let mut _7: i32; let mut _8: i32; + let mut _10: i32; + let mut _11: i32; + let mut _13: i32; + let mut _14: i32; + let mut _16: i32; + let mut _17: i32; + let mut _19: i32; + let mut _20: i32; + let mut _22: i32; + let mut _23: i32; scope 1 { - debug _x => _3; + debug _a => _3; let _6: i32; scope 2 { - debug _y => _6; + debug _b => _6; + let _9: i32; + scope 3 { + debug _c => _9; + let _12: i32; + scope 4 { + debug _x => _12; + let _15: i32; + scope 5 { + debug _y => _15; + let _18: i32; + scope 6 { + debug _i => _18; + let _21: i32; + scope 7 { + debug _j => _21; + } + } + } + } + } } } @@ -24,8 +54,8 @@ _4 = _1; StorageLive(_5); _5 = _2; -- _3 = unchecked_div::<i32>(move _4, move _5) -> [return: bb1, unwind unreachable]; -+ _3 = Div(move _4, move _5); +- _3 = unchecked_add::<i32>(move _4, move _5) -> [return: bb1, unwind unreachable]; ++ _3 = AddUnchecked(move _4, move _5); + goto -> bb1; } @@ -37,15 +67,85 @@ _7 = _1; StorageLive(_8); _8 = _2; -- _6 = unchecked_rem::<i32>(move _7, move _8) -> [return: bb2, unwind unreachable]; -+ _6 = Rem(move _7, move _8); +- _6 = unchecked_sub::<i32>(move _7, move _8) -> [return: bb2, unwind unreachable]; ++ _6 = SubUnchecked(move _7, move _8); + goto -> bb2; } bb2: { StorageDead(_8); StorageDead(_7); + StorageLive(_9); + StorageLive(_10); + _10 = _1; + StorageLive(_11); + _11 = _2; +- _9 = unchecked_mul::<i32>(move _10, move _11) -> [return: bb3, unwind unreachable]; ++ _9 = MulUnchecked(move _10, move _11); ++ goto -> bb3; + } + + bb3: { + StorageDead(_11); + StorageDead(_10); + StorageLive(_12); + StorageLive(_13); + _13 = _1; + StorageLive(_14); + _14 = _2; +- _12 = unchecked_div::<i32>(move _13, move _14) -> [return: bb4, unwind unreachable]; ++ _12 = Div(move _13, move _14); ++ goto -> bb4; + } + + bb4: { + StorageDead(_14); + StorageDead(_13); + StorageLive(_15); + StorageLive(_16); + _16 = _1; + StorageLive(_17); + _17 = _2; +- _15 = unchecked_rem::<i32>(move _16, move _17) -> [return: bb5, unwind unreachable]; ++ _15 = Rem(move _16, move _17); ++ goto -> bb5; + } + + bb5: { + StorageDead(_17); + StorageDead(_16); + StorageLive(_18); + StorageLive(_19); + _19 = _1; + StorageLive(_20); + _20 = _2; +- _18 = unchecked_shl::<i32>(move _19, move _20) -> [return: bb6, unwind unreachable]; ++ _18 = ShlUnchecked(move _19, move _20); ++ goto -> bb6; + } + + bb6: { + StorageDead(_20); + StorageDead(_19); + StorageLive(_21); + StorageLive(_22); + _22 = _1; + StorageLive(_23); + _23 = _2; +- _21 = unchecked_shr::<i32>(move _22, move _23) -> [return: bb7, unwind unreachable]; ++ _21 = ShrUnchecked(move _22, move _23); ++ goto -> bb7; + } + + bb7: { + StorageDead(_23); + StorageDead(_22); _0 = const (); + StorageDead(_21); + StorageDead(_18); + StorageDead(_15); + StorageDead(_12); + StorageDead(_9); StorageDead(_6); StorageDead(_3); return; diff --git a/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-unwind.diff index c532d74ced0..dd92b8d6d2c 100644 --- a/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-unwind.diff +++ b/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-unwind.diff @@ -10,11 +10,41 @@ let mut _5: i32; let mut _7: i32; let mut _8: i32; + let mut _10: i32; + let mut _11: i32; + let mut _13: i32; + let mut _14: i32; + let mut _16: i32; + let mut _17: i32; + let mut _19: i32; + let mut _20: i32; + let mut _22: i32; + let mut _23: i32; scope 1 { - debug _x => _3; + debug _a => _3; let _6: i32; scope 2 { - debug _y => _6; + debug _b => _6; + let _9: i32; + scope 3 { + debug _c => _9; + let _12: i32; + scope 4 { + debug _x => _12; + let _15: i32; + scope 5 { + debug _y => _15; + let _18: i32; + scope 6 { + debug _i => _18; + let _21: i32; + scope 7 { + debug _j => _21; + } + } + } + } + } } } @@ -24,8 +54,8 @@ _4 = _1; StorageLive(_5); _5 = _2; -- _3 = unchecked_div::<i32>(move _4, move _5) -> [return: bb1, unwind unreachable]; -+ _3 = Div(move _4, move _5); +- _3 = unchecked_add::<i32>(move _4, move _5) -> [return: bb1, unwind unreachable]; ++ _3 = AddUnchecked(move _4, move _5); + goto -> bb1; } @@ -37,15 +67,85 @@ _7 = _1; StorageLive(_8); _8 = _2; -- _6 = unchecked_rem::<i32>(move _7, move _8) -> [return: bb2, unwind unreachable]; -+ _6 = Rem(move _7, move _8); +- _6 = unchecked_sub::<i32>(move _7, move _8) -> [return: bb2, unwind unreachable]; ++ _6 = SubUnchecked(move _7, move _8); + goto -> bb2; } bb2: { StorageDead(_8); StorageDead(_7); + StorageLive(_9); + StorageLive(_10); + _10 = _1; + StorageLive(_11); + _11 = _2; +- _9 = unchecked_mul::<i32>(move _10, move _11) -> [return: bb3, unwind unreachable]; ++ _9 = MulUnchecked(move _10, move _11); ++ goto -> bb3; + } + + bb3: { + StorageDead(_11); + StorageDead(_10); + StorageLive(_12); + StorageLive(_13); + _13 = _1; + StorageLive(_14); + _14 = _2; +- _12 = unchecked_div::<i32>(move _13, move _14) -> [return: bb4, unwind unreachable]; ++ _12 = Div(move _13, move _14); ++ goto -> bb4; + } + + bb4: { + StorageDead(_14); + StorageDead(_13); + StorageLive(_15); + StorageLive(_16); + _16 = _1; + StorageLive(_17); + _17 = _2; +- _15 = unchecked_rem::<i32>(move _16, move _17) -> [return: bb5, unwind unreachable]; ++ _15 = Rem(move _16, move _17); ++ goto -> bb5; + } + + bb5: { + StorageDead(_17); + StorageDead(_16); + StorageLive(_18); + StorageLive(_19); + _19 = _1; + StorageLive(_20); + _20 = _2; +- _18 = unchecked_shl::<i32>(move _19, move _20) -> [return: bb6, unwind unreachable]; ++ _18 = ShlUnchecked(move _19, move _20); ++ goto -> bb6; + } + + bb6: { + StorageDead(_20); + StorageDead(_19); + StorageLive(_21); + StorageLive(_22); + _22 = _1; + StorageLive(_23); + _23 = _2; +- _21 = unchecked_shr::<i32>(move _22, move _23) -> [return: bb7, unwind unreachable]; ++ _21 = ShrUnchecked(move _22, move _23); ++ goto -> bb7; + } + + bb7: { + StorageDead(_23); + StorageDead(_22); _0 = const (); + StorageDead(_21); + StorageDead(_18); + StorageDead(_15); + StorageDead(_12); + StorageDead(_9); StorageDead(_6); StorageDead(_3); return; diff --git a/tests/mir-opt/pre-codegen/chained_comparison.naive.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/chained_comparison.naive.PreCodegen.after.mir index 1c74ae74d53..c7fd397fcd4 100644 --- a/tests/mir-opt/pre-codegen/chained_comparison.naive.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/chained_comparison.naive.PreCodegen.after.mir @@ -7,26 +7,26 @@ fn naive(_1: &Blueprint, _2: &Blueprint) -> bool { let mut _3: u32; let mut _4: u32; let mut _5: bool; - let mut _6: u32; + let mut _6: bool; let mut _7: u32; - let mut _8: bool; + let mut _8: u32; let mut _9: bool; - let mut _10: u32; + let mut _10: bool; let mut _11: u32; - let mut _12: bool; + let mut _12: u32; let mut _13: bool; - let mut _14: u32; + let mut _14: bool; let mut _15: u32; - let mut _16: bool; + let mut _16: u32; let mut _17: bool; let mut _18: u32; let mut _19: u32; let mut _20: bool; bb0: { - StorageLive(_17); - StorageLive(_13); - StorageLive(_9); + StorageLive(_14); + StorageLive(_10); + StorageLive(_6); StorageLive(_5); StorageLive(_3); _3 = ((*_1).0: u32); @@ -39,74 +39,83 @@ fn naive(_1: &Blueprint, _2: &Blueprint) -> bool { } bb1: { - StorageDead(_8); - StorageDead(_5); + _6 = const false; goto -> bb3; } bb2: { - StorageLive(_8); - StorageLive(_6); - _6 = ((*_1).1: u32); + StorageLive(_9); StorageLive(_7); - _7 = ((*_2).1: u32); - _8 = Eq(move _6, move _7); - StorageDead(_7); - StorageDead(_6); - _9 = move _8; + _7 = ((*_1).1: u32); + StorageLive(_8); + _8 = ((*_2).1: u32); + _9 = Eq(move _7, move _8); StorageDead(_8); - StorageDead(_5); - switchInt(move _9) -> [0: bb3, otherwise: bb4]; + StorageDead(_7); + _6 = move _9; + goto -> bb3; } bb3: { - StorageDead(_12); StorageDead(_9); - goto -> bb5; + StorageDead(_5); + switchInt(move _6) -> [0: bb4, otherwise: bb5]; } bb4: { - StorageLive(_12); - StorageLive(_10); - _10 = ((*_1).2: u32); - StorageLive(_11); - _11 = ((*_2).2: u32); - _12 = Eq(move _10, move _11); - StorageDead(_11); - StorageDead(_10); - _13 = move _12; - StorageDead(_12); - StorageDead(_9); - switchInt(move _13) -> [0: bb5, otherwise: bb6]; + _10 = const false; + goto -> bb6; } bb5: { - StorageDead(_16); - StorageDead(_13); - goto -> bb7; + StorageLive(_13); + StorageLive(_11); + _11 = ((*_1).2: u32); + StorageLive(_12); + _12 = ((*_2).2: u32); + _13 = Eq(move _11, move _12); + StorageDead(_12); + StorageDead(_11); + _10 = move _13; + goto -> bb6; } bb6: { - StorageLive(_16); - StorageLive(_14); - _14 = ((*_1).3: u32); - StorageLive(_15); - _15 = ((*_2).3: u32); - _16 = Eq(move _14, move _15); - StorageDead(_15); - StorageDead(_14); - _17 = move _16; - StorageDead(_16); StorageDead(_13); - switchInt(move _17) -> [0: bb7, otherwise: bb8]; + StorageDead(_6); + switchInt(move _10) -> [0: bb7, otherwise: bb8]; } bb7: { - _0 = const false; + _14 = const false; goto -> bb9; } bb8: { + StorageLive(_17); + StorageLive(_15); + _15 = ((*_1).3: u32); + StorageLive(_16); + _16 = ((*_2).3: u32); + _17 = Eq(move _15, move _16); + StorageDead(_16); + StorageDead(_15); + _14 = move _17; + goto -> bb9; + } + + bb9: { + StorageDead(_17); + StorageDead(_10); + switchInt(move _14) -> [0: bb10, otherwise: bb11]; + } + + bb10: { + _0 = const false; + goto -> bb12; + } + + bb11: { StorageLive(_20); StorageLive(_18); _18 = ((*_1).4: u32); @@ -116,12 +125,12 @@ fn naive(_1: &Blueprint, _2: &Blueprint) -> bool { StorageDead(_19); StorageDead(_18); _0 = move _20; - goto -> bb9; + goto -> bb12; } - bb9: { + bb12: { StorageDead(_20); - StorageDead(_17); + StorageDead(_14); return; } } diff --git a/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir index 10b93a15799..800308c2e0b 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir @@ -7,17 +7,16 @@ fn checked_shl(_1: u32, _2: u32) -> Option<u32> { scope 1 (inlined core::num::<impl u32>::checked_shl) { debug self => _1; debug rhs => _2; - let mut _11: u32; - let mut _12: bool; + let mut _7: bool; scope 2 { - debug a => _11; - debug b => _10; + debug a => _5; + debug b => _6; } scope 3 (inlined core::num::<impl u32>::overflowing_shl) { debug self => _1; debug rhs => _2; - let mut _9: u32; - let mut _10: bool; + let mut _5: u32; + let mut _6: bool; scope 4 (inlined core::num::<impl u32>::wrapping_shl) { debug self => _1; debug rhs => _2; @@ -27,52 +26,7 @@ fn checked_shl(_1: u32, _2: u32) -> Option<u32> { scope 6 (inlined core::num::<impl u32>::unchecked_shl) { debug self => _1; debug rhs => _4; - let mut _8: u32; scope 7 { - scope 8 (inlined core::num::<impl u32>::unchecked_shl::conv) { - debug x => _4; - let mut _5: std::result::Result<u32, std::convert::Infallible>; - let mut _7: std::option::Option<u32>; - scope 9 { - scope 10 (inlined <u32 as TryInto<u32>>::try_into) { - debug self => _4; - scope 11 (inlined <u32 as TryFrom<u32>>::try_from) { - debug value => _4; - scope 12 (inlined <u32 as Into<u32>>::into) { - debug self => _4; - scope 13 (inlined <u32 as From<u32>>::from) { - debug t => _4; - } - } - } - } - scope 14 (inlined Result::<u32, Infallible>::ok) { - debug self => _5; - let _6: u32; - scope 15 { - debug x => _6; - } - } - scope 16 (inlined #[track_caller] Option::<u32>::unwrap_unchecked) { - debug self => _7; - let mut _13: &std::option::Option<u32>; - scope 17 { - debug val => _8; - } - scope 18 { - scope 20 (inlined unreachable_unchecked) { - scope 21 { - scope 22 (inlined unreachable_unchecked::runtime) { - } - } - } - } - scope 19 (inlined Option::<u32>::is_some) { - debug self => _13; - } - } - } - } } } } @@ -81,58 +35,38 @@ fn checked_shl(_1: u32, _2: u32) -> Option<u32> { } bb0: { - StorageLive(_10); - StorageLive(_11); - StorageLive(_9); + StorageLive(_5); + StorageLive(_6); StorageLive(_4); StorageLive(_3); _3 = const 31_u32; _4 = BitAnd(_2, move _3); StorageDead(_3); - StorageLive(_8); + _5 = ShlUnchecked(_1, _4); + StorageDead(_4); + _6 = Ge(_2, const _); StorageLive(_7); - StorageLive(_5); - _5 = Result::<u32, Infallible>::Ok(_4); - StorageLive(_6); - _6 = move ((_5 as Ok).0: u32); - _7 = Option::<u32>::Some(move _6); - StorageDead(_6); - StorageDead(_5); - StorageLive(_13); - _8 = move ((_7 as Some).0: u32); - StorageDead(_13); - StorageDead(_7); - _9 = unchecked_shl::<u32>(_1, move _8) -> [return: bb1, unwind unreachable]; + _7 = unlikely(_6) -> [return: bb1, unwind unreachable]; } bb1: { - StorageDead(_8); - StorageDead(_4); - _10 = Ge(_2, const _); - _11 = move _9; - StorageDead(_9); - StorageLive(_12); - _12 = unlikely(_10) -> [return: bb2, unwind unreachable]; + switchInt(move _7) -> [0: bb2, otherwise: bb3]; } bb2: { - switchInt(move _12) -> [0: bb3, otherwise: bb4]; + _0 = Option::<u32>::Some(_5); + goto -> bb4; } bb3: { - _0 = Option::<u32>::Some(_11); - goto -> bb5; - } - - bb4: { _0 = Option::<u32>::None; - goto -> bb5; + goto -> bb4; } - bb5: { - StorageDead(_12); - StorageDead(_11); - StorageDead(_10); + bb4: { + StorageDead(_7); + StorageDead(_6); + StorageDead(_5); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir index 6c1d5096db0..499bee2ae40 100644 --- a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir @@ -14,10 +14,10 @@ fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:7:25: 7:39], _2 let _12: &usize; let mut _13: &&usize; let mut _18: bool; - let mut _19: &&usize; - let _20: &usize; - let mut _21: &&usize; - let mut _26: bool; + let mut _19: bool; + let mut _20: &&usize; + let _21: &usize; + let mut _22: &&usize; let mut _27: bool; let mut _28: &&usize; let _29: &usize; @@ -58,15 +58,15 @@ fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:7:25: 7:39], _2 } } scope 6 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { - debug self => _19; - debug other => _21; - let mut _22: &usize; + debug self => _20; + debug other => _22; let mut _23: &usize; + let mut _24: &usize; scope 7 (inlined cmp::impls::<impl PartialOrd for usize>::le) { - debug self => _22; - debug other => _23; - let mut _24: usize; + debug self => _23; + debug other => _24; let mut _25: usize; + let mut _26: usize; } } scope 8 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { @@ -96,7 +96,7 @@ fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:7:25: 7:39], _2 StorageLive(_10); _9 = deref_copy (*_2); _10 = &((*_9).3: usize); - StorageLive(_27); + StorageLive(_19); StorageLive(_18); StorageLive(_11); _11 = &_4; @@ -120,38 +120,41 @@ fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:7:25: 7:39], _2 } bb1: { - StorageDead(_26); - StorageDead(_18); + _19 = const false; goto -> bb3; } bb2: { - StorageLive(_26); - StorageLive(_19); - _19 = &_10; - StorageLive(_21); + StorageLive(_27); StorageLive(_20); - _20 = _6; - _21 = &_20; - _22 = deref_copy (*_19); - _23 = deref_copy (*_21); - StorageLive(_24); - _24 = (*_22); + _20 = &_10; + StorageLive(_22); + StorageLive(_21); + _21 = _6; + _22 = &_21; + _23 = deref_copy (*_20); + _24 = deref_copy (*_22); StorageLive(_25); _25 = (*_23); - _26 = Le(move _24, move _25); + StorageLive(_26); + _26 = (*_24); + _27 = Le(move _25, move _26); + StorageDead(_26); StorageDead(_25); - StorageDead(_24); - StorageDead(_20); StorageDead(_21); - StorageDead(_19); - _27 = move _26; - StorageDead(_26); - StorageDead(_18); - switchInt(move _27) -> [0: bb3, otherwise: bb7]; + StorageDead(_22); + StorageDead(_20); + _19 = move _27; + goto -> bb3; } bb3: { + StorageDead(_27); + StorageDead(_18); + switchInt(move _19) -> [0: bb4, otherwise: bb8]; + } + + bb4: { StorageLive(_36); StorageLive(_35); StorageLive(_28); @@ -172,15 +175,15 @@ fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:7:25: 7:39], _2 StorageDead(_29); StorageDead(_30); StorageDead(_28); - switchInt(move _35) -> [0: bb4, otherwise: bb5]; + switchInt(move _35) -> [0: bb5, otherwise: bb6]; } - bb4: { + bb5: { _36 = const false; - goto -> bb6; + goto -> bb7; } - bb5: { + bb6: { StorageLive(_44); StorageLive(_37); _37 = &_6; @@ -201,24 +204,24 @@ fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:7:25: 7:39], _2 StorageDead(_39); StorageDead(_37); _36 = move _44; - goto -> bb6; + goto -> bb7; } - bb6: { + bb7: { StorageDead(_44); StorageDead(_35); _0 = move _36; - goto -> bb8; + goto -> bb9; } - bb7: { + bb8: { _0 = const true; - goto -> bb8; + goto -> bb9; } - bb8: { + bb9: { StorageDead(_36); - StorageDead(_27); + StorageDead(_19); StorageDead(_10); StorageDead(_8); StorageDead(_6); diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir index ef1036d5faf..bab9f0b58aa 100644 --- a/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir @@ -32,61 +32,64 @@ fn variant_b::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:11:25: 11:41], _8 = ((*_7).2: usize); _9 = deref_copy (*_2); _10 = ((*_9).3: usize); - StorageLive(_13); + StorageLive(_12); StorageLive(_11); _11 = Le(_4, _8); switchInt(move _11) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageDead(_12); - StorageDead(_11); + _12 = const false; goto -> bb3; } bb2: { - StorageLive(_12); - _12 = Le(_10, _6); - _13 = move _12; - StorageDead(_12); - StorageDead(_11); - switchInt(move _13) -> [0: bb3, otherwise: bb7]; + StorageLive(_13); + _13 = Le(_10, _6); + _12 = move _13; + goto -> bb3; } bb3: { + StorageDead(_13); + StorageDead(_11); + switchInt(move _12) -> [0: bb4, otherwise: bb8]; + } + + bb4: { StorageLive(_15); StorageLive(_14); _14 = Le(_8, _4); - switchInt(move _14) -> [0: bb4, otherwise: bb5]; + switchInt(move _14) -> [0: bb5, otherwise: bb6]; } - bb4: { + bb5: { _15 = const false; - goto -> bb6; + goto -> bb7; } - bb5: { + bb6: { StorageLive(_16); _16 = Le(_6, _10); _15 = move _16; - goto -> bb6; + goto -> bb7; } - bb6: { + bb7: { StorageDead(_16); StorageDead(_14); _0 = move _15; - goto -> bb8; + goto -> bb9; } - bb7: { + bb8: { _0 = const true; - goto -> bb8; + goto -> bb9; } - bb8: { + bb9: { StorageDead(_15); - StorageDead(_13); + StorageDead(_12); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir index 79282d88905..a337ca89992 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir @@ -10,58 +10,44 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> debug self => _1; debug index => std::ops::Range<usize>{ .0 => _3, .1 => _4, }; let mut _5: *mut [u32]; - let mut _14: *mut [u32]; + let mut _13: *mut [u32]; scope 2 { scope 3 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) { debug self => std::ops::Range<usize>{ .0 => _3, .1 => _4, }; debug slice => _5; let mut _7: *mut u32; let mut _8: *mut u32; - let mut _9: usize; - let _16: usize; - let _17: usize; + let _14: usize; + let _15: usize; scope 4 { - debug this => std::ops::Range<usize>{ .0 => _16, .1 => _17, }; + debug this => std::ops::Range<usize>{ .0 => _14, .1 => _15, }; scope 5 { let _6: usize; scope 6 { debug new_len => _6; - scope 11 (inlined ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) { + scope 7 (inlined ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) { debug self => _5; } - scope 12 (inlined ptr::mut_ptr::<impl *mut u32>::add) { + scope 8 (inlined ptr::mut_ptr::<impl *mut u32>::add) { debug self => _7; debug count => _3; - scope 13 { + scope 9 { } } - scope 14 (inlined slice_from_raw_parts_mut::<u32>) { + scope 10 (inlined slice_from_raw_parts_mut::<u32>) { debug data => _8; - debug len => _9; - let mut _10: *mut (); - scope 15 (inlined ptr::mut_ptr::<impl *mut u32>::cast::<()>) { + debug len => _6; + let mut _9: *mut (); + scope 11 (inlined ptr::mut_ptr::<impl *mut u32>::cast::<()>) { debug self => _8; } - scope 16 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { - debug data_address => _10; - debug metadata => _9; - let mut _11: *const (); - let mut _12: std::ptr::metadata::PtrComponents<[u32]>; - let mut _13: std::ptr::metadata::PtrRepr<[u32]>; - scope 17 { - } - } - } - } - scope 7 (inlined <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::runtime::<u32>) { - debug this => std::ops::Range<usize>{ .0 => _16, .1 => _17, }; - debug slice => _5; - scope 8 (inlined ptr::mut_ptr::<impl *mut [u32]>::len) { - debug self => _5; - let mut _15: *const [u32]; - scope 9 (inlined std::ptr::metadata::<[u32]>) { - debug ptr => _15; - scope 10 { + scope 12 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { + debug data_address => _9; + debug metadata => _6; + let mut _10: *const (); + let mut _11: std::ptr::metadata::PtrComponents<[u32]>; + let mut _12: std::ptr::metadata::PtrRepr<[u32]>; + scope 13 { } } } @@ -75,46 +61,38 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> bb0: { _3 = move (_2.0: usize); _4 = move (_2.1: usize); - StorageLive(_14); + StorageLive(_13); StorageLive(_5); _5 = &raw mut (*_1); + StorageLive(_14); StorageLive(_15); - StorageLive(_16); - StorageLive(_17); StorageLive(_6); - _6 = unchecked_sub::<usize>(_4, _3) -> [return: bb1, unwind unreachable]; - } - - bb1: { + _6 = SubUnchecked(_4, _3); StorageLive(_8); StorageLive(_7); _7 = _5 as *mut u32 (PtrToPtr); _8 = Offset(_7, _3); StorageDead(_7); StorageLive(_9); - _9 = _6; - StorageLive(_10); - _10 = _8 as *mut () (PtrToPtr); - StorageLive(_13); + _9 = _8 as *mut () (PtrToPtr); StorageLive(_12); StorageLive(_11); - _11 = _10 as *const () (Pointer(MutToConstPointer)); - _12 = ptr::metadata::PtrComponents::<[u32]> { data_address: move _11, metadata: _9 }; + StorageLive(_10); + _10 = _9 as *const () (Pointer(MutToConstPointer)); + _11 = ptr::metadata::PtrComponents::<[u32]> { data_address: move _10, metadata: _6 }; + StorageDead(_10); + _12 = ptr::metadata::PtrRepr::<[u32]> { const_ptr: move _11 }; StorageDead(_11); - _13 = ptr::metadata::PtrRepr::<[u32]> { const_ptr: move _12 }; + _13 = (_12.1: *mut [u32]); StorageDead(_12); - _14 = (_13.1: *mut [u32]); - StorageDead(_13); - StorageDead(_10); StorageDead(_9); StorageDead(_8); StorageDead(_6); - StorageDead(_17); - StorageDead(_16); + StorageDead(_14); StorageDead(_15); StorageDead(_5); - _0 = &mut (*_14); - StorageDead(_14); + _0 = &mut (*_13); + StorageDead(_13); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir index 79282d88905..a337ca89992 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir @@ -10,58 +10,44 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> debug self => _1; debug index => std::ops::Range<usize>{ .0 => _3, .1 => _4, }; let mut _5: *mut [u32]; - let mut _14: *mut [u32]; + let mut _13: *mut [u32]; scope 2 { scope 3 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) { debug self => std::ops::Range<usize>{ .0 => _3, .1 => _4, }; debug slice => _5; let mut _7: *mut u32; let mut _8: *mut u32; - let mut _9: usize; - let _16: usize; - let _17: usize; + let _14: usize; + let _15: usize; scope 4 { - debug this => std::ops::Range<usize>{ .0 => _16, .1 => _17, }; + debug this => std::ops::Range<usize>{ .0 => _14, .1 => _15, }; scope 5 { let _6: usize; scope 6 { debug new_len => _6; - scope 11 (inlined ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) { + scope 7 (inlined ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) { debug self => _5; } - scope 12 (inlined ptr::mut_ptr::<impl *mut u32>::add) { + scope 8 (inlined ptr::mut_ptr::<impl *mut u32>::add) { debug self => _7; debug count => _3; - scope 13 { + scope 9 { } } - scope 14 (inlined slice_from_raw_parts_mut::<u32>) { + scope 10 (inlined slice_from_raw_parts_mut::<u32>) { debug data => _8; - debug len => _9; - let mut _10: *mut (); - scope 15 (inlined ptr::mut_ptr::<impl *mut u32>::cast::<()>) { + debug len => _6; + let mut _9: *mut (); + scope 11 (inlined ptr::mut_ptr::<impl *mut u32>::cast::<()>) { debug self => _8; } - scope 16 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { - debug data_address => _10; - debug metadata => _9; - let mut _11: *const (); - let mut _12: std::ptr::metadata::PtrComponents<[u32]>; - let mut _13: std::ptr::metadata::PtrRepr<[u32]>; - scope 17 { - } - } - } - } - scope 7 (inlined <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::runtime::<u32>) { - debug this => std::ops::Range<usize>{ .0 => _16, .1 => _17, }; - debug slice => _5; - scope 8 (inlined ptr::mut_ptr::<impl *mut [u32]>::len) { - debug self => _5; - let mut _15: *const [u32]; - scope 9 (inlined std::ptr::metadata::<[u32]>) { - debug ptr => _15; - scope 10 { + scope 12 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { + debug data_address => _9; + debug metadata => _6; + let mut _10: *const (); + let mut _11: std::ptr::metadata::PtrComponents<[u32]>; + let mut _12: std::ptr::metadata::PtrRepr<[u32]>; + scope 13 { } } } @@ -75,46 +61,38 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> bb0: { _3 = move (_2.0: usize); _4 = move (_2.1: usize); - StorageLive(_14); + StorageLive(_13); StorageLive(_5); _5 = &raw mut (*_1); + StorageLive(_14); StorageLive(_15); - StorageLive(_16); - StorageLive(_17); StorageLive(_6); - _6 = unchecked_sub::<usize>(_4, _3) -> [return: bb1, unwind unreachable]; - } - - bb1: { + _6 = SubUnchecked(_4, _3); StorageLive(_8); StorageLive(_7); _7 = _5 as *mut u32 (PtrToPtr); _8 = Offset(_7, _3); StorageDead(_7); StorageLive(_9); - _9 = _6; - StorageLive(_10); - _10 = _8 as *mut () (PtrToPtr); - StorageLive(_13); + _9 = _8 as *mut () (PtrToPtr); StorageLive(_12); StorageLive(_11); - _11 = _10 as *const () (Pointer(MutToConstPointer)); - _12 = ptr::metadata::PtrComponents::<[u32]> { data_address: move _11, metadata: _9 }; + StorageLive(_10); + _10 = _9 as *const () (Pointer(MutToConstPointer)); + _11 = ptr::metadata::PtrComponents::<[u32]> { data_address: move _10, metadata: _6 }; + StorageDead(_10); + _12 = ptr::metadata::PtrRepr::<[u32]> { const_ptr: move _11 }; StorageDead(_11); - _13 = ptr::metadata::PtrRepr::<[u32]> { const_ptr: move _12 }; + _13 = (_12.1: *mut [u32]); StorageDead(_12); - _14 = (_13.1: *mut [u32]); - StorageDead(_13); - StorageDead(_10); StorageDead(_9); StorageDead(_8); StorageDead(_6); - StorageDead(_17); - StorageDead(_16); + StorageDead(_14); StorageDead(_15); StorageDead(_5); - _0 = &mut (*_14); - StorageDead(_14); + _0 = &mut (*_13); + StorageDead(_13); return; } } diff --git a/tests/mir-opt/separate_const_switch.rs b/tests/mir-opt/separate_const_switch.rs index c809e5629cc..d333d4b6be2 100644 --- a/tests/mir-opt/separate_const_switch.rs +++ b/tests/mir-opt/separate_const_switch.rs @@ -1,6 +1,8 @@ #![feature(control_flow_enum)] #![feature(try_trait_v2)] +// compile-flags: -Zunsound-mir-opts + use std::ops::ControlFlow; // EMIT_MIR separate_const_switch.too_complex.SeparateConstSwitch.diff diff --git a/tests/run-make-fulldeps/issue-19371/foo.rs b/tests/run-make-fulldeps/issue-19371/foo.rs index 6d08cfd07f8..9cca6200050 100644 --- a/tests/run-make-fulldeps/issue-19371/foo.rs +++ b/tests/run-make-fulldeps/issue-19371/foo.rs @@ -63,10 +63,11 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) { }; interface::run_compiler(config, |compiler| { - // This runs all the passes prior to linking, too. - let linker = compiler.enter(|queries| queries.linker()); - if let Ok(linker) = linker { - linker.link(); - } + let linker = compiler.enter(|queries| { + queries.global_ctxt()?.enter(|tcx| tcx.analysis(()))?; + let ongoing_codegen = queries.ongoing_codegen()?; + queries.linker(ongoing_codegen) + }); + linker.unwrap().link(); }); } diff --git a/tests/run-make/allocator-shim-circular-deps/Makefile b/tests/run-make/allocator-shim-circular-deps/Makefile new file mode 100644 index 00000000000..4624b846803 --- /dev/null +++ b/tests/run-make/allocator-shim-circular-deps/Makefile @@ -0,0 +1,7 @@ +# ignore-cross-compile +include ../tools.mk + +all: + rm -rf $(TMPDIR) && mkdir $(TMPDIR) + $(RUSTC) my_lib.rs + $(RUSTC) main.rs --test --extern my_lib=$(TMPDIR)/libmy_lib.rlib diff --git a/tests/run-make/allocator-shim-circular-deps/main.rs b/tests/run-make/allocator-shim-circular-deps/main.rs new file mode 100644 index 00000000000..e317c657150 --- /dev/null +++ b/tests/run-make/allocator-shim-circular-deps/main.rs @@ -0,0 +1,5 @@ +#![crate_type = "bin"] + +fn main() { + my_lib::do_something(); +} diff --git a/tests/run-make/allocator-shim-circular-deps/my_lib.rs b/tests/run-make/allocator-shim-circular-deps/my_lib.rs new file mode 100644 index 00000000000..095b1036116 --- /dev/null +++ b/tests/run-make/allocator-shim-circular-deps/my_lib.rs @@ -0,0 +1,10 @@ +#![crate_type = "lib"] + +use std::alloc::System; + +#[global_allocator] +static ALLOCATOR: System = System; + +pub fn do_something() { + format!("allocating a string!"); +} diff --git a/tests/run-make/coverage-reports/sort_subviews.py b/tests/run-make/coverage-reports/sort_subviews.py index 10cfc51d447..10cfc51d447 100644..100755 --- a/tests/run-make/coverage-reports/sort_subviews.py +++ b/tests/run-make/coverage-reports/sort_subviews.py diff --git a/tests/run-make/libtest-junit/validate_junit.py b/tests/run-make/libtest-junit/validate_junit.py index 47a8e70ccc3..0d9b34a3cf7 100755 --- a/tests/run-make/libtest-junit/validate_junit.py +++ b/tests/run-make/libtest-junit/validate_junit.py @@ -7,6 +7,6 @@ import xml.etree.ElementTree as ET for line in sys.stdin: try: ET.fromstring(line) - except ET.ParseError as pe: + except ET.ParseError: print("Invalid xml: %r" % line) raise diff --git a/tests/run-make/rustdoc-map-file/validate_json.py b/tests/run-make/rustdoc-map-file/validate_json.py index 5c14c90b70d..912dea3791b 100755 --- a/tests/run-make/rustdoc-map-file/validate_json.py +++ b/tests/run-make/rustdoc-map-file/validate_json.py @@ -6,7 +6,7 @@ import json def find_redirect_map_file(folder, errors): - for root, dirs, files in os.walk(folder): + for root, _dirs, files in os.walk(folder): for name in files: if not name.endswith("redirect-map.json"): continue diff --git a/tests/run-make/sysroot-crates-are-unstable/test.py b/tests/run-make/sysroot-crates-are-unstable/test.py index cab4faa4e64..45cfdd195b4 100644 --- a/tests/run-make/sysroot-crates-are-unstable/test.py +++ b/tests/run-make/sysroot-crates-are-unstable/test.py @@ -46,7 +46,7 @@ def check_lib(lib): '--target', os.environ['TARGET'], '--extern', '{}={}'.format(lib['name'], lib['path'])], to_input=('extern crate {};'.format(lib['name'])).encode('utf-8')) - if not 'use of unstable library feature' in '{}{}'.format(stdout, stderr): + if 'use of unstable library feature' not in '{}{}'.format(stdout, stderr): print('crate {} "{}" is not unstable'.format(lib['name'], lib['path'])) print('{}{}'.format(stdout, stderr)) print('') diff --git a/tests/run-make/target-specs/Makefile b/tests/run-make/target-specs/Makefile index a33f5368e3c..62d5365a73d 100644 --- a/tests/run-make/target-specs/Makefile +++ b/tests/run-make/target-specs/Makefile @@ -8,4 +8,5 @@ all: RUST_TARGET_PATH=. $(RUSTC) foo.rs --target=my-x86_64-unknown-linux-gnu-platform --crate-type=lib --emit=asm $(RUSTC) -Z unstable-options --target=my-awesome-platform.json --print target-spec-json > $(TMPDIR)/test-platform.json && $(RUSTC) -Z unstable-options --target=$(TMPDIR)/test-platform.json --print target-spec-json | diff -q $(TMPDIR)/test-platform.json - $(RUSTC) foo.rs --target=definitely-not-builtin-target 2>&1 | $(CGREP) 'may not set is_builtin' + $(RUSTC) foo.rs --target=endianness-mismatch 2>&1 | $(CGREP) '"data-layout" claims architecture is little-endian' $(RUSTC) foo.rs --target=mismatching-data-layout --crate-type=lib diff --git a/tests/run-make/target-specs/endianness-mismatch.json b/tests/run-make/target-specs/endianness-mismatch.json new file mode 100644 index 00000000000..431053ea99b --- /dev/null +++ b/tests/run-make/target-specs/endianness-mismatch.json @@ -0,0 +1,11 @@ +{ + "pre-link-args": {"gcc": ["-m64"]}, + "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128", + "linker-flavor": "gcc", + "llvm-target": "x86_64-unknown-linux-gnu", + "target-endian": "big", + "target-pointer-width": "64", + "target-c-int-width": "32", + "arch": "x86_64", + "os": "linux" +} diff --git a/tests/rustdoc-gui/fields.goml b/tests/rustdoc-gui/fields.goml new file mode 100644 index 00000000000..b8139a2edac --- /dev/null +++ b/tests/rustdoc-gui/fields.goml @@ -0,0 +1,18 @@ +// This test checks that fields are displayed as expected (one by line). +go-to: "file://" + |DOC_PATH| + "/test_docs/fields/struct.Struct.html" +store-position: ("#structfield\.a", {"y": a_y}) +store-position: ("#structfield\.b", {"y": b_y}) +assert: |a_y| < |b_y| + +go-to: "file://" + |DOC_PATH| + "/test_docs/fields/union.Union.html" +store-position: ("#structfield\.a", {"y": a_y}) +store-position: ("#structfield\.b", {"y": b_y}) +assert: |a_y| < |b_y| + +go-to: "file://" + |DOC_PATH| + "/test_docs/fields/enum.Enum.html" +store-position: ("#variant\.A\.field\.a", {"y": a_y}) +store-position: ("#variant\.A\.field\.b", {"y": b_y}) +assert: |a_y| < |b_y| +store-position: ("#variant\.B\.field\.a", {"y": a_y}) +store-position: ("#variant\.B\.field\.b", {"y": b_y}) +assert: |a_y| < |b_y| diff --git a/tests/rustdoc-gui/help-page.goml b/tests/rustdoc-gui/help-page.goml index 1a1c1b28f61..6e880302f28 100644 --- a/tests/rustdoc-gui/help-page.goml +++ b/tests/rustdoc-gui/help-page.goml @@ -67,5 +67,5 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" set-window-size: (1000, 1000) // Popover only appears when the screen width is >700px. assert-false: "#help" click: "#help-button > a" -click: ".popover a[href='https://doc.rust-lang.org/rustdoc/']" -wait-for-document-property: {"URL": "https://doc.rust-lang.org/rustdoc/"} +click: "//*[@id='help']//a[text()='the rustdoc book']" +wait-for-document-property: ({"URL": "https://doc.rust-lang.org/"}, STARTS_WITH) diff --git a/tests/rustdoc-gui/search-result-color.goml b/tests/rustdoc-gui/search-result-color.goml index c75e4141434..e3c628b366f 100644 --- a/tests/rustdoc-gui/search-result-color.goml +++ b/tests/rustdoc-gui/search-result-color.goml @@ -28,6 +28,12 @@ define-function: ( ".result-" + |result_kind| + ":focus ." + |result_kind|, {"color": |hover_color|}, ) + // color of the typename (struct, module, method, ...) before search results + assert-css: ( + ".result-name .typename", + {"color": |grey|}, + ALL, + ) }, ) @@ -69,6 +75,7 @@ store-value: (entry_color, "#0096cf") // color of the search entry store-value: (hover_entry_color, "#fff") // color of the hovered/focused search entry store-value: (background_color, "transparent") // background color store-value: (hover_background_color, "#3c3c3c") // hover background color +store-value: (grey, "#999") call-function: ( "check-result-color", ( @@ -180,6 +187,7 @@ store-value: (entry_color, "#ddd") // color of the search entry store-value: (hover_entry_color, "#ddd") // color of the hovered/focused search entry store-value: (background_color, "transparent") // background color store-value: (hover_background_color, "#616161") // hover background color +store-value: (grey, "#ccc") call-function: ( "check-result-color", ( @@ -276,6 +284,7 @@ store-value: (entry_color, "#000") // color of the search entry store-value: (hover_entry_color, "#000") // color of the hovered/focused search entry store-value: (background_color, "transparent") // background color store-value: (hover_background_color, "#ccc") // hover background color +store-value: (grey, "#999") call-function: ( "check-result-color", ( diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs index 6ad1e8b4f67..c040fa02dff 100644 --- a/tests/rustdoc-gui/src/test_docs/lib.rs +++ b/tests/rustdoc-gui/src/test_docs/lib.rs @@ -486,3 +486,24 @@ pub mod search_results { } } + +pub mod fields { + pub struct Struct { + pub a: u8, + pub b: u32, + } + pub union Union { + pub a: u8, + pub b: u32, + } + pub enum Enum { + A { + a: u8, + b: u32, + }, + B { + a: u8, + b: u32, + }, + } +} diff --git a/tests/rustdoc/alias-reexport.rs b/tests/rustdoc/alias-reexport.rs new file mode 100644 index 00000000000..a2a8e651caf --- /dev/null +++ b/tests/rustdoc/alias-reexport.rs @@ -0,0 +1,16 @@ +// aux-build:alias-reexport.rs +// aux-build:alias-reexport2.rs + +#![crate_name = "foo"] +#![feature(lazy_type_alias)] + +extern crate alias_reexport2; + +// @has 'foo/reexport/fn.foo.html' +// @has - '//*[@class="rust item-decl"]' 'pub fn foo() -> Reexported' +// @has 'foo/reexport/fn.foo2.html' +// @has - '//*[@class="rust item-decl"]' 'pub fn foo2() -> Result<Reexported, ()>' +// @has 'foo/reexport/type.Reexported.html' +// @has - '//*[@class="rust item-decl"]' 'pub type Reexported = u8;' +#[doc(inline)] +pub use alias_reexport2 as reexport; diff --git a/tests/rustdoc/alias-reexport2.rs b/tests/rustdoc/alias-reexport2.rs new file mode 100644 index 00000000000..85d3cdad962 --- /dev/null +++ b/tests/rustdoc/alias-reexport2.rs @@ -0,0 +1,16 @@ +// gate-test-lazy_type_alias +// aux-build:alias-reexport.rs + +#![crate_name = "foo"] +#![feature(lazy_type_alias)] + +extern crate alias_reexport; + +use alias_reexport::Reexported; + +// @has 'foo/fn.foo.html' +// @has - '//*[@class="rust item-decl"]' 'pub fn foo() -> Reexported' +pub fn foo() -> Reexported { 0 } +// @has 'foo/fn.foo2.html' +// @has - '//*[@class="rust item-decl"]' 'pub fn foo2() -> Result<Reexported, ()>' +pub fn foo2() -> Result<Reexported, ()> { Ok(0) } diff --git a/tests/rustdoc/auxiliary/alias-reexport.rs b/tests/rustdoc/auxiliary/alias-reexport.rs new file mode 100644 index 00000000000..14fafc02d36 --- /dev/null +++ b/tests/rustdoc/auxiliary/alias-reexport.rs @@ -0,0 +1,3 @@ +#![feature(lazy_type_alias)] + +pub type Reexported = u8; diff --git a/tests/rustdoc/auxiliary/alias-reexport2.rs b/tests/rustdoc/auxiliary/alias-reexport2.rs new file mode 100644 index 00000000000..9f6910572ad --- /dev/null +++ b/tests/rustdoc/auxiliary/alias-reexport2.rs @@ -0,0 +1,12 @@ +#![feature(lazy_type_alias)] + +extern crate alias_reexport; + +pub use alias_reexport::Reexported; + +// @has 'foo/fn.foo.html' +// @has - '//*[@class="docblock item-decl"]' 'pub fn foo() -> Reexported' +pub fn foo() -> Reexported { 0 } +// @has 'foo/fn.foo2.html' +// @has - '//*[@class="docblock item-decl"]' 'pub fn foo2() -> Result<Reexported, ()>' +pub fn foo2() -> Result<Reexported, ()> { Ok(0) } diff --git a/tests/rustdoc/files-creation-hidden.rs b/tests/rustdoc/files-creation-hidden.rs new file mode 100644 index 00000000000..498d9cdaef1 --- /dev/null +++ b/tests/rustdoc/files-creation-hidden.rs @@ -0,0 +1,24 @@ +#![crate_name="foo"] + +// @files foo '["index.html", "all.html", "sidebar-items.js"]' +// @!has "foo/struct.Foo.html" +#[doc(hidden)] +pub struct Foo; + +// @!has "foo/struct.Bar.html" +pub use crate::Foo as Bar; + +// @!has "foo/struct.Baz.html" +#[doc(hidden)] +pub use crate::Foo as Baz; + +// @!has "foo/foo/index.html" +#[doc(hidden)] +pub mod foo {} + +// @!has "foo/bar/index.html" +pub use crate::foo as bar; + +// @!has "foo/baz/index.html" +#[doc(hidden)] +pub use crate::foo as baz; diff --git a/tests/rustdoc/files-creation-private.rs b/tests/rustdoc/files-creation-private.rs new file mode 100644 index 00000000000..e2fdbc068f8 --- /dev/null +++ b/tests/rustdoc/files-creation-private.rs @@ -0,0 +1,22 @@ +#![crate_name="foo"] + +// @files "foo" \ +// '["index.html", "all.html", "sidebar-items.js", "foo", "bar", "private", "struct.Bar.html"]' +// @files "foo/bar" '["index.html", "sidebar-items.js"]' + +// @!has "foo/priv/index.html" +// @!has "foo/priv/struct.Foo.html" +mod private { + pub struct Foo; +} + +// @has "foo/struct.Bar.html" +pub use crate::private::Foo as Bar; + +// @!has "foo/foo/index.html" +mod foo { + pub mod subfoo {} +} + +// @has "foo/bar/index.html" +pub use crate::foo::subfoo as bar; diff --git a/tests/rustdoc/issue-111064-reexport-trait-from-hidden-2.rs b/tests/rustdoc/issue-111064-reexport-trait-from-hidden-2.rs index 8e1029a1ca3..65c26d6a837 100644 --- a/tests/rustdoc/issue-111064-reexport-trait-from-hidden-2.rs +++ b/tests/rustdoc/issue-111064-reexport-trait-from-hidden-2.rs @@ -2,11 +2,17 @@ #![no_core] #![crate_name = "foo"] +// @files "foo" "['sidebar-items.js', 'all.html', 'hidden', 'index.html', 'struct.Bar.html', \ +// 'visible']" +// @files "foo/hidden" "['inner']" +// @files "foo/hidden/inner" "['trait.Foo.html']" +// @files "foo/visible" "['index.html', 'sidebar-items.js', 'trait.Foo.html']" + // @!has 'foo/hidden/index.html' -// FIXME: add missing `@` for the two next tests once issue is fixed! -// To be done in <https://github.com/rust-lang/rust/issues/111249>. -// !has 'foo/hidden/inner/index.html' -// !has 'foo/hidden/inner/trait.Foo.html' +// @!has 'foo/hidden/inner/index.html' +// FIXME: Should be `@!has`: https://github.com/rust-lang/rust/issues/111249 +// @has 'foo/hidden/inner/trait.Foo.html' +// @matchesraw - '<meta http-equiv="refresh" content="0;URL=../../../foo/visible/trait.Foo.html">' #[doc(hidden)] pub mod hidden { pub mod inner { diff --git a/tests/rustdoc/issue-111249-file-creation.rs b/tests/rustdoc/issue-111249-file-creation.rs new file mode 100644 index 00000000000..afd65ddaf94 --- /dev/null +++ b/tests/rustdoc/issue-111249-file-creation.rs @@ -0,0 +1,40 @@ +#![crate_name = "foo"] +#![feature(no_core)] +#![no_core] + +// @files "foo" "['all.html', 'visible', 'index.html', 'sidebar-items.js', 'hidden', \ +// 'struct.Bar.html']" +// @files "foo/visible" "['trait.Foo.html', 'index.html', 'sidebar-items.js']" +// @files "foo/hidden" "['inner']" +// @files "foo/hidden/inner" "['trait.Foo.html']" + +// The following five should not fail! +// @!has 'foo/hidden/index.html' +// @!has 'foo/hidden/inner/index.html' +// FIXME: Should be `@!has`: https://github.com/rust-lang/rust/issues/111249 +// @has 'foo/hidden/inner/trait.Foo.html' +// @matchesraw - '<meta http-equiv="refresh" content="0;URL=../../../foo/visible/trait.Foo.html">' +// @!has 'foo/hidden/inner/inner_hidden/index.html' +// @!has 'foo/hidden/inner/inner_hidden/trait.HiddenFoo.html' +#[doc(hidden)] +pub mod hidden { + pub mod inner { + pub trait Foo {} + + #[doc(hidden)] + pub mod inner_hidden { + pub trait HiddenFoo {} + } + } +} + +// @has 'foo/visible/index.html' +// @has 'foo/visible/trait.Foo.html' +#[doc(inline)] +pub use hidden::inner as visible; + +// @has 'foo/struct.Bar.html' +// @count - '//*[@id="impl-Foo-for-Bar"]' 1 +pub struct Bar; + +impl visible::Foo for Bar {} diff --git a/tests/rustdoc/redirect.rs b/tests/rustdoc/redirect.rs index 5b7a76e1a77..4fb81c23d39 100644 --- a/tests/rustdoc/redirect.rs +++ b/tests/rustdoc/redirect.rs @@ -10,7 +10,9 @@ pub trait Foo {} // @has - '//code' 'pub use reexp_stripped::Bar' // @has - '//code/a' 'Bar' // @has - '//a[@href="../reexp_stripped/hidden/struct.Bar.html"]' 'Bar' +// FIXME: Should be `@!has`: https://github.com/rust-lang/rust/issues/111249 // @has reexp_stripped/hidden/struct.Bar.html +// @matchesraw - '<meta http-equiv="refresh" content="0;URL=../../reexp_stripped/struct.Bar.html">' // @has 'reexp_stripped/struct.Bar.html' // @has - '//a[@href="struct.Bar.html"]' 'Bar' #[doc(no_inline)] diff --git a/tests/rustdoc/union-fields-html.rs b/tests/rustdoc/union-fields-html.rs new file mode 100644 index 00000000000..1ac01232c3e --- /dev/null +++ b/tests/rustdoc/union-fields-html.rs @@ -0,0 +1,11 @@ +#![crate_name = "foo"] + +// @has 'foo/union.Union.html' +// Checking that there is a whitespace after `:`. +// @has - '//*[@id="structfield.a"]/code' 'a: u8' +// @has - '//*[@id="structfield.b"]/code' 'b: u32' +pub union Union { + pub a: u8, + /// tadam + pub b: u32, +} diff --git a/tests/rustdoc/where.SWhere_Echo_impl.html b/tests/rustdoc/where.SWhere_Echo_impl.html new file mode 100644 index 00000000000..7517eb090f4 --- /dev/null +++ b/tests/rustdoc/where.SWhere_Echo_impl.html @@ -0,0 +1,2 @@ +<h3 class="code-header">impl<D> <a class="struct" href="struct.Delta.html" title="struct foo::Delta">Delta</a><D><span class="where fmt-newline">where + D: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a>,</span></h3> \ No newline at end of file diff --git a/tests/rustdoc/where.SWhere_Simd_item-decl.html b/tests/rustdoc/where.SWhere_Simd_item-decl.html index ef4294c8f76..3e72ba2b74f 100644 --- a/tests/rustdoc/where.SWhere_Simd_item-decl.html +++ b/tests/rustdoc/where.SWhere_Simd_item-decl.html @@ -1,3 +1,3 @@ <pre class="rust item-decl"><code>pub struct Simd<T>(_) <span class="where">where - T: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code></pre> \ No newline at end of file + T: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code></pre> diff --git a/tests/rustdoc/where.alpha_trait_decl.html b/tests/rustdoc/where.alpha_trait_decl.html new file mode 100644 index 00000000000..a7700055c9a --- /dev/null +++ b/tests/rustdoc/where.alpha_trait_decl.html @@ -0,0 +1,3 @@ +<code>pub struct Alpha<A>(_) +<span class="where">where + A: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code> \ No newline at end of file diff --git a/tests/rustdoc/where.bravo_trait_decl.html b/tests/rustdoc/where.bravo_trait_decl.html new file mode 100644 index 00000000000..00524201a8a --- /dev/null +++ b/tests/rustdoc/where.bravo_trait_decl.html @@ -0,0 +1,5 @@ +<code>pub trait Bravo<B><span class="where fmt-newline">where + B: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a>,</span>{ + // Required method + fn <a href="#tymethod.get" class="fn">get</a>(&self, B: B); +}</code> \ No newline at end of file diff --git a/tests/rustdoc/where.charlie_fn_decl.html b/tests/rustdoc/where.charlie_fn_decl.html new file mode 100644 index 00000000000..8e3bc8b01ec --- /dev/null +++ b/tests/rustdoc/where.charlie_fn_decl.html @@ -0,0 +1,2 @@ +<code>pub fn charlie<C>()<span class="where fmt-newline">where + C: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a>,</span></code> \ No newline at end of file diff --git a/tests/rustdoc/where.golf_type_alias_decl.html b/tests/rustdoc/where.golf_type_alias_decl.html new file mode 100644 index 00000000000..8da5402f900 --- /dev/null +++ b/tests/rustdoc/where.golf_type_alias_decl.html @@ -0,0 +1,2 @@ +<code>pub type Golf<T><span class="where fmt-newline">where + T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>,</span> = <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T, T)</a>;</code> \ No newline at end of file diff --git a/tests/rustdoc/where.rs b/tests/rustdoc/where.rs index 8b8a126e89d..2aa9c8b5461 100644 --- a/tests/rustdoc/where.rs +++ b/tests/rustdoc/where.rs @@ -5,16 +5,20 @@ use std::io::Lines; pub trait MyTrait { fn dummy(&self) { } } // @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_) where A: MyTrait" +// @snapshot alpha_trait_decl - '//*[@class="rust item-decl"]/code' pub struct Alpha<A>(A) where A: MyTrait; // @has foo/trait.Bravo.html '//pre' "pub trait Bravo<B>where B: MyTrait" +// @snapshot bravo_trait_decl - '//*[@class="rust item-decl"]/code' pub trait Bravo<B> where B: MyTrait { fn get(&self, B: B); } // @has foo/fn.charlie.html '//pre' "pub fn charlie<C>()where C: MyTrait" +// @snapshot charlie_fn_decl - '//*[@class="rust item-decl"]/code' pub fn charlie<C>() where C: MyTrait {} pub struct Delta<D>(D); // @has foo/struct.Delta.html '//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<D> Delta<D>where D: MyTrait" +// @snapshot SWhere_Echo_impl - '//*[@id="impl-Delta%3CD%3E"]/h3[@class="code-header"]' impl<D> Delta<D> where D: MyTrait { pub fn delta() {} } @@ -65,4 +69,5 @@ impl<F> MyTrait for Foxtrot<F>where F: MyTrait {} // @has foo/type.Golf.html '//pre[@class="rust item-decl"]' \ // "type Golf<T>where T: Clone, = (T, T)" +// @snapshot golf_type_alias_decl - '//*[@class="rust item-decl"]/code' pub type Golf<T> where T: Clone = (T, T); diff --git a/tests/ui/argument-suggestions/issue-112507.rs b/tests/ui/argument-suggestions/issue-112507.rs new file mode 100644 index 00000000000..61743c59a4a --- /dev/null +++ b/tests/ui/argument-suggestions/issue-112507.rs @@ -0,0 +1,12 @@ +pub enum Value { + Float(Option<f64>), +} + +fn main() { + let _a = Value::Float( //~ ERROR this enum variant takes 1 argument but 4 arguments were supplied + 0, + None, + None, + 0, + ); +} diff --git a/tests/ui/argument-suggestions/issue-112507.stderr b/tests/ui/argument-suggestions/issue-112507.stderr new file mode 100644 index 00000000000..dfb47e010e4 --- /dev/null +++ b/tests/ui/argument-suggestions/issue-112507.stderr @@ -0,0 +1,27 @@ +error[E0061]: this enum variant takes 1 argument but 4 arguments were supplied + --> $DIR/issue-112507.rs:6:14 + | +LL | let _a = Value::Float( + | ^^^^^^^^^^^^ +LL | 0, + | - unexpected argument of type `{integer}` +LL | None, +LL | None, + | ---- unexpected argument of type `Option<_>` +LL | 0, + | - unexpected argument of type `{integer}` + | +note: tuple variant defined here + --> $DIR/issue-112507.rs:2:5 + | +LL | Float(Option<f64>), + | ^^^^^ +help: remove the extra arguments + | +LL ~ , +LL ~ None); + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0061`. diff --git a/tests/ui/asm/aarch64/may_unwind.rs b/tests/ui/asm/aarch64/may_unwind.rs index 6af8728bbaa..cfb75078264 100644 --- a/tests/ui/asm/aarch64/may_unwind.rs +++ b/tests/ui/asm/aarch64/may_unwind.rs @@ -1,6 +1,7 @@ // only-aarch64 // run-pass // needs-asm-support +// needs-unwind #![feature(asm_unwind)] diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.current.stderr index 95ef7d82fca..b8be132e6b6 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.current.stderr @@ -1,11 +1,11 @@ error: return type notation uses `()` instead of `(..)` for elided arguments - --> $DIR/bad-inputs-and-output.rs:18:24 + --> $DIR/bad-inputs-and-output.rs:20:24 | LL | fn baz<T: Trait<method(..): Send>>() {} | ^^ help: remove the `..` error[E0658]: associated type bounds are unstable - --> $DIR/bad-inputs-and-output.rs:10:17 + --> $DIR/bad-inputs-and-output.rs:12:17 | LL | fn foo<T: Trait<method(i32): Send>>() {} | ^^^^^^^^^^^^^^^^^ @@ -14,7 +14,7 @@ LL | fn foo<T: Trait<method(i32): Send>>() {} = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable error[E0658]: associated type bounds are unstable - --> $DIR/bad-inputs-and-output.rs:14:17 + --> $DIR/bad-inputs-and-output.rs:16:17 | LL | fn bar<T: Trait<method() -> (): Send>>() {} | ^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | fn bar<T: Trait<method() -> (): Send>>() {} = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/bad-inputs-and-output.rs:3:12 + --> $DIR/bad-inputs-and-output.rs:5:12 | LL | #![feature(return_type_notation, async_fn_in_trait)] | ^^^^^^^^^^^^^^^^^^^^ @@ -32,13 +32,13 @@ LL | #![feature(return_type_notation, async_fn_in_trait)] = note: `#[warn(incomplete_features)]` on by default error: argument types not allowed with return type notation - --> $DIR/bad-inputs-and-output.rs:10:23 + --> $DIR/bad-inputs-and-output.rs:12:23 | LL | fn foo<T: Trait<method(i32): Send>>() {} | ^^^^^ help: remove the input types: `()` error: return type not allowed with return type notation - --> $DIR/bad-inputs-and-output.rs:14:25 + --> $DIR/bad-inputs-and-output.rs:16:25 | LL | fn bar<T: Trait<method() -> (): Send>>() {} | ^^^^^^ help: remove the return type diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.next.stderr b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.next.stderr new file mode 100644 index 00000000000..b8be132e6b6 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.next.stderr @@ -0,0 +1,48 @@ +error: return type notation uses `()` instead of `(..)` for elided arguments + --> $DIR/bad-inputs-and-output.rs:20:24 + | +LL | fn baz<T: Trait<method(..): Send>>() {} + | ^^ help: remove the `..` + +error[E0658]: associated type bounds are unstable + --> $DIR/bad-inputs-and-output.rs:12:17 + | +LL | fn foo<T: Trait<method(i32): Send>>() {} + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #52662 <https://github.com/rust-lang/rust/issues/52662> for more information + = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable + +error[E0658]: associated type bounds are unstable + --> $DIR/bad-inputs-and-output.rs:16:17 + | +LL | fn bar<T: Trait<method() -> (): Send>>() {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #52662 <https://github.com/rust-lang/rust/issues/52662> for more information + = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable + +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/bad-inputs-and-output.rs:5:12 + | +LL | #![feature(return_type_notation, async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information + = note: `#[warn(incomplete_features)]` on by default + +error: argument types not allowed with return type notation + --> $DIR/bad-inputs-and-output.rs:12:23 + | +LL | fn foo<T: Trait<method(i32): Send>>() {} + | ^^^^^ help: remove the input types: `()` + +error: return type not allowed with return type notation + --> $DIR/bad-inputs-and-output.rs:16:25 + | +LL | fn bar<T: Trait<method() -> (): Send>>() {} + | ^^^^^^ help: remove the return type + +error: aborting due to 5 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs index 58ce41d1a89..771acb6c4e7 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs @@ -1,4 +1,6 @@ // edition: 2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(return_type_notation, async_fn_in_trait)] //~^ WARN the feature `return_type_notation` is incomplete diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.current_with.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.current_with.stderr new file mode 100644 index 00000000000..98c1a282779 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.current_with.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/basic.rs:8:12 + | +LL | #![feature(return_type_notation, async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.current_without.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.current_without.stderr new file mode 100644 index 00000000000..1066c420c31 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.current_without.stderr @@ -0,0 +1,29 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/basic.rs:8:12 + | +LL | #![feature(return_type_notation, async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information + = note: `#[warn(incomplete_features)]` on by default + +error: future cannot be sent between threads safely + --> $DIR/basic.rs:26:13 + | +LL | is_send(foo::<T>()); + | ^^^^^^^^^^ future returned by `foo` is not `Send` + | + = help: within `impl Future<Output = Result<(), ()>>`, the trait `Send` is not implemented for `impl Future<Output = Result<(), ()>>` +note: future is not `Send` as it awaits another future which is not `Send` + --> $DIR/basic.rs:16:5 + | +LL | T::method().await?; + | ^^^^^^^^^^^ await occurs here on type `impl Future<Output = Result<(), ()>>`, which is not `Send` +note: required by a bound in `is_send` + --> $DIR/basic.rs:20:20 + | +LL | fn is_send(_: impl Send) {} + | ^^^^ required by this bound in `is_send` + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.next_with.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.next_with.stderr new file mode 100644 index 00000000000..98c1a282779 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.next_with.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/basic.rs:8:12 + | +LL | #![feature(return_type_notation, async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.next_without.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.next_without.stderr new file mode 100644 index 00000000000..1066c420c31 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.next_without.stderr @@ -0,0 +1,29 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/basic.rs:8:12 + | +LL | #![feature(return_type_notation, async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information + = note: `#[warn(incomplete_features)]` on by default + +error: future cannot be sent between threads safely + --> $DIR/basic.rs:26:13 + | +LL | is_send(foo::<T>()); + | ^^^^^^^^^^ future returned by `foo` is not `Send` + | + = help: within `impl Future<Output = Result<(), ()>>`, the trait `Send` is not implemented for `impl Future<Output = Result<(), ()>>` +note: future is not `Send` as it awaits another future which is not `Send` + --> $DIR/basic.rs:16:5 + | +LL | T::method().await?; + | ^^^^^^^^^^^ await occurs here on type `impl Future<Output = Result<(), ()>>`, which is not `Send` +note: required by a bound in `is_send` + --> $DIR/basic.rs:20:20 + | +LL | fn is_send(_: impl Send) {} + | ^^^^ required by this bound in `is_send` + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.rs b/tests/ui/associated-type-bounds/return-type-notation/basic.rs index edc6a8e4caf..d443c9dc11b 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.rs @@ -1,6 +1,9 @@ -// revisions: with without +// revisions: current_with current_without next_with next_without +// [next_with] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// [next_without] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty // edition: 2021 -//[with] check-pass +// [current_with] check-pass +// [next_with] check-pass #![feature(return_type_notation, async_fn_in_trait)] //~^ WARN the feature `return_type_notation` is incomplete @@ -17,11 +20,12 @@ async fn foo<T: Foo>() -> Result<(), ()> { fn is_send(_: impl Send) {} fn test< - #[cfg(with)] T: Foo<method(): Send>, - #[cfg(without)] T: Foo, + #[cfg(any(current_with, next_with))] T: Foo<method(): Send>, + #[cfg(any(current_without, next_without))] T: Foo, >() { is_send(foo::<T>()); - //[without]~^ ERROR future cannot be sent between threads safely + //[current_without]~^ ERROR future cannot be sent between threads safely + //[next_without]~^^ ERROR future cannot be sent between threads safely } fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.stderr b/tests/ui/associated-type-bounds/return-type-notation/equality.current.stderr index 490bfdc4c3c..b631dd0ebb5 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/equality.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/equality.current.stderr @@ -1,5 +1,5 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/equality.rs:3:12 + --> $DIR/equality.rs:5:12 | LL | #![feature(return_type_notation, async_fn_in_trait)] | ^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #![feature(return_type_notation, async_fn_in_trait)] = note: `#[warn(incomplete_features)]` on by default error: return type notation is not allowed to use type equality - --> $DIR/equality.rs:12:18 + --> $DIR/equality.rs:14:18 | LL | fn test<T: Trait<method() = Box<dyn Future<Output = ()>>>>() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.next.stderr b/tests/ui/associated-type-bounds/return-type-notation/equality.next.stderr new file mode 100644 index 00000000000..b631dd0ebb5 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/equality.next.stderr @@ -0,0 +1,17 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/equality.rs:5:12 + | +LL | #![feature(return_type_notation, async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information + = note: `#[warn(incomplete_features)]` on by default + +error: return type notation is not allowed to use type equality + --> $DIR/equality.rs:14:18 + | +LL | fn test<T: Trait<method() = Box<dyn Future<Output = ()>>>>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.rs b/tests/ui/associated-type-bounds/return-type-notation/equality.rs index 6884305d7b3..0d6545cc298 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/equality.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/equality.rs @@ -1,4 +1,6 @@ // edition: 2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(return_type_notation, async_fn_in_trait)] //~^ WARN the feature `return_type_notation` is incomplete diff --git a/tests/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr b/tests/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr index 721234aa4a7..f80bb4242aa 100644 --- a/tests/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr +++ b/tests/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr @@ -1,18 +1,25 @@ -error[E0277]: `Sender<i32>` cannot be shared between threads safely - --> $DIR/issue-70935-complex-spans.rs:13:45 +error[E0277]: `*mut ()` cannot be shared between threads safely + --> $DIR/issue-70935-complex-spans.rs:18:23 | -LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send { - | ^^^^^^^^^^^^^^^^^^ `Sender<i32>` cannot be shared between threads safely +LL | fn foo(x: NotSync) -> impl Future + Send { + | ^^^^^^^^^^^^^^^^^^ `*mut ()` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `Sender<i32>` - = note: required for `&Sender<i32>` to implement `Send` + = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()` +note: required because it appears within the type `PhantomData<*mut ()>` + --> $SRC_DIR/core/src/marker.rs:LL:COL +note: required because it appears within the type `NotSync` + --> $DIR/issue-70935-complex-spans.rs:12:8 + | +LL | struct NotSync(PhantomData<*mut ()>); + | ^^^^^^^ + = note: required for `&NotSync` to implement `Send` note: required because it's used within this closure - --> $DIR/issue-70935-complex-spans.rs:17:13 + --> $DIR/issue-70935-complex-spans.rs:22:13 | -LL | baz(|| async{ +LL | baz(|| async { | ^^ note: required because it's used within this `async fn` body - --> $DIR/issue-70935-complex-spans.rs:10:67 + --> $DIR/issue-70935-complex-spans.rs:15:67 | LL | async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> { | ___________________________________________________________________^ @@ -20,11 +27,11 @@ LL | | } | |_^ = note: required because it captures the following types: `ResumeTy`, `impl Future<Output = ()>`, `()` note: required because it's used within this `async` block - --> $DIR/issue-70935-complex-spans.rs:16:5 + --> $DIR/issue-70935-complex-spans.rs:21:5 | LL | / async move { -LL | | baz(|| async{ -LL | | foo(tx.clone()); +LL | | baz(|| async { +LL | | foo(x.clone()); LL | | }).await; LL | | } | |_____^ diff --git a/tests/ui/async-await/issue-70935-complex-spans.drop_tracking_mir.stderr b/tests/ui/async-await/issue-70935-complex-spans.drop_tracking_mir.stderr index c636be15a58..eb9d93e229f 100644 --- a/tests/ui/async-await/issue-70935-complex-spans.drop_tracking_mir.stderr +++ b/tests/ui/async-await/issue-70935-complex-spans.drop_tracking_mir.stderr @@ -1,18 +1,25 @@ -error[E0277]: `Sender<i32>` cannot be shared between threads safely - --> $DIR/issue-70935-complex-spans.rs:13:45 +error[E0277]: `*mut ()` cannot be shared between threads safely + --> $DIR/issue-70935-complex-spans.rs:18:23 | -LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send { - | ^^^^^^^^^^^^^^^^^^ `Sender<i32>` cannot be shared between threads safely +LL | fn foo(x: NotSync) -> impl Future + Send { + | ^^^^^^^^^^^^^^^^^^ `*mut ()` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `Sender<i32>` - = note: required for `&Sender<i32>` to implement `Send` + = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()` +note: required because it appears within the type `PhantomData<*mut ()>` + --> $SRC_DIR/core/src/marker.rs:LL:COL +note: required because it appears within the type `NotSync` + --> $DIR/issue-70935-complex-spans.rs:12:8 + | +LL | struct NotSync(PhantomData<*mut ()>); + | ^^^^^^^ + = note: required for `&NotSync` to implement `Send` note: required because it's used within this closure - --> $DIR/issue-70935-complex-spans.rs:17:13 + --> $DIR/issue-70935-complex-spans.rs:22:13 | -LL | baz(|| async{ +LL | baz(|| async { | ^^ note: required because it's used within this `async fn` body - --> $DIR/issue-70935-complex-spans.rs:10:67 + --> $DIR/issue-70935-complex-spans.rs:15:67 | LL | async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> { | ___________________________________________________________________^ @@ -20,11 +27,11 @@ LL | | } | |_^ = note: required because it captures the following types: `impl Future<Output = ()>` note: required because it's used within this `async` block - --> $DIR/issue-70935-complex-spans.rs:16:5 + --> $DIR/issue-70935-complex-spans.rs:21:5 | LL | / async move { -LL | | baz(|| async{ -LL | | foo(tx.clone()); +LL | | baz(|| async { +LL | | foo(x.clone()); LL | | }).await; LL | | } | |_____^ diff --git a/tests/ui/async-await/issue-70935-complex-spans.no_drop_tracking.stderr b/tests/ui/async-await/issue-70935-complex-spans.no_drop_tracking.stderr index ef0e182e515..d8ef6a5eedb 100644 --- a/tests/ui/async-await/issue-70935-complex-spans.no_drop_tracking.stderr +++ b/tests/ui/async-await/issue-70935-complex-spans.no_drop_tracking.stderr @@ -1,21 +1,21 @@ error: future cannot be sent between threads safely - --> $DIR/issue-70935-complex-spans.rs:13:45 + --> $DIR/issue-70935-complex-spans.rs:18:23 | -LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send { - | ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` +LL | fn foo(x: NotSync) -> impl Future + Send { + | ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` | - = help: the trait `Sync` is not implemented for `Sender<i32>` + = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()` note: future is not `Send` as this value is used across an await - --> $DIR/issue-70935-complex-spans.rs:19:12 + --> $DIR/issue-70935-complex-spans.rs:24:12 | -LL | baz(|| async{ +LL | baz(|| async { | _____________- -LL | | foo(tx.clone()); +LL | | foo(x.clone()); LL | | }).await; | | - ^^^^^- the value is later dropped here | | | | | |_________| await occurs here, with the value maybe used later - | has type `[closure@$DIR/issue-70935-complex-spans.rs:17:13: 17:15]` which is not `Send` + | has type `[closure@$DIR/issue-70935-complex-spans.rs:22:13: 22:15]` which is not `Send` error: aborting due to previous error diff --git a/tests/ui/async-await/issue-70935-complex-spans.rs b/tests/ui/async-await/issue-70935-complex-spans.rs index 78625bd393d..9ebde1d3977 100644 --- a/tests/ui/async-await/issue-70935-complex-spans.rs +++ b/tests/ui/async-await/issue-70935-complex-spans.rs @@ -6,16 +6,21 @@ // with newlines which lead complex diagnostics. use std::future::Future; +use std::marker::PhantomData; + +#[derive(Clone)] +struct NotSync(PhantomData<*mut ()>); +unsafe impl Send for NotSync {} async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> { } -fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send { +fn foo(x: NotSync) -> impl Future + Send { //[no_drop_tracking]~^ ERROR future cannot be sent between threads safely - //[drop_tracking,drop_tracking_mir]~^^ ERROR `Sender<i32>` cannot be shared between threads + //[drop_tracking,drop_tracking_mir]~^^ ERROR `*mut ()` cannot be shared between threads async move { - baz(|| async{ - foo(tx.clone()); + baz(|| async { + foo(x.clone()); }).await; } } @@ -24,6 +29,6 @@ fn bar(_s: impl Future + Send) { } fn main() { - let (tx, _rx) = std::sync::mpsc::channel(); - bar(foo(tx)); + let x = NotSync(PhantomData); + bar(foo(x)); } diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr b/tests/ui/async-await/return-type-notation/issue-110963-early.current.stderr index 33e22dec3f7..1b847b59eb5 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.current.stderr @@ -1,5 +1,5 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-110963-early.rs:4:12 + --> $DIR/issue-110963-early.rs:6:12 | LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #![feature(return_type_notation)] = note: `#[warn(incomplete_features)]` on by default error: higher-ranked lifetime error - --> $DIR/issue-110963-early.rs:15:5 + --> $DIR/issue-110963-early.rs:17:5 | LL | / spawn(async move { LL | | let mut hc = hc; @@ -18,10 +18,10 @@ LL | | } LL | | }); | |______^ | - = note: could not prove `[async block@$DIR/issue-110963-early.rs:15:11: 20:6]: Send` + = note: could not prove `[async block@$DIR/issue-110963-early.rs:17:11: 22:6]: Send` error: higher-ranked lifetime error - --> $DIR/issue-110963-early.rs:15:5 + --> $DIR/issue-110963-early.rs:17:5 | LL | / spawn(async move { LL | | let mut hc = hc; @@ -31,7 +31,7 @@ LL | | } LL | | }); | |______^ | - = note: could not prove `[async block@$DIR/issue-110963-early.rs:15:11: 20:6]: Send` + = note: could not prove `[async block@$DIR/issue-110963-early.rs:17:11: 22:6]: Send` error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.next.stderr b/tests/ui/async-await/return-type-notation/issue-110963-early.next.stderr new file mode 100644 index 00000000000..1b847b59eb5 --- /dev/null +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.next.stderr @@ -0,0 +1,37 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-110963-early.rs:6:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information + = note: `#[warn(incomplete_features)]` on by default + +error: higher-ranked lifetime error + --> $DIR/issue-110963-early.rs:17:5 + | +LL | / spawn(async move { +LL | | let mut hc = hc; +LL | | if !hc.check().await { +LL | | log_health_check_failure().await; +LL | | } +LL | | }); + | |______^ + | + = note: could not prove `[async block@$DIR/issue-110963-early.rs:17:11: 22:6]: Send` + +error: higher-ranked lifetime error + --> $DIR/issue-110963-early.rs:17:5 + | +LL | / spawn(async move { +LL | | let mut hc = hc; +LL | | if !hc.check().await { +LL | | log_health_check_failure().await; +LL | | } +LL | | }); + | |______^ + | + = note: could not prove `[async block@$DIR/issue-110963-early.rs:17:11: 22:6]: Send` + +error: aborting due to 2 previous errors; 1 warning emitted + diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.rs b/tests/ui/async-await/return-type-notation/issue-110963-early.rs index 0ecbca5c13b..eee31aa1fe5 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-early.rs +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.rs @@ -1,5 +1,7 @@ // edition: 2021 // known-bug: #110963 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(return_type_notation)] #![feature(async_fn_in_trait)] diff --git a/tests/ui/async-await/return-type-notation/issue-110963-late.stderr b/tests/ui/async-await/return-type-notation/issue-110963-late.current.stderr index 9c6966537a7..018f4f2207a 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-late.stderr +++ b/tests/ui/async-await/return-type-notation/issue-110963-late.current.stderr @@ -1,5 +1,5 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-110963-late.rs:4:12 + --> $DIR/issue-110963-late.rs:6:12 | LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/return-type-notation/issue-110963-late.next.stderr b/tests/ui/async-await/return-type-notation/issue-110963-late.next.stderr new file mode 100644 index 00000000000..018f4f2207a --- /dev/null +++ b/tests/ui/async-await/return-type-notation/issue-110963-late.next.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-110963-late.rs:6:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/async-await/return-type-notation/issue-110963-late.rs b/tests/ui/async-await/return-type-notation/issue-110963-late.rs index 17b5d775d44..ea047cd3b16 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-late.rs +++ b/tests/ui/async-await/return-type-notation/issue-110963-late.rs @@ -1,5 +1,7 @@ // edition: 2021 // check-pass +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(return_type_notation)] //~^ WARN the feature `return_type_notation` is incomplete diff --git a/tests/ui/async-await/return-type-notation/super-method-bound.stderr b/tests/ui/async-await/return-type-notation/super-method-bound.current.stderr index ac0668d3c44..891c802c5f4 100644 --- a/tests/ui/async-await/return-type-notation/super-method-bound.stderr +++ b/tests/ui/async-await/return-type-notation/super-method-bound.current.stderr @@ -1,5 +1,5 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/super-method-bound.rs:4:31 + --> $DIR/super-method-bound.rs:6:31 | LL | #![feature(async_fn_in_trait, return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/return-type-notation/super-method-bound.next.stderr b/tests/ui/async-await/return-type-notation/super-method-bound.next.stderr new file mode 100644 index 00000000000..891c802c5f4 --- /dev/null +++ b/tests/ui/async-await/return-type-notation/super-method-bound.next.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/super-method-bound.rs:6:31 + | +LL | #![feature(async_fn_in_trait, return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/async-await/return-type-notation/super-method-bound.rs b/tests/ui/async-await/return-type-notation/super-method-bound.rs index 58ea3578db6..0163c62f545 100644 --- a/tests/ui/async-await/return-type-notation/super-method-bound.rs +++ b/tests/ui/async-await/return-type-notation/super-method-bound.rs @@ -1,5 +1,7 @@ // edition:2021 // check-pass +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait, return_type_notation)] //~^ WARN the feature `return_type_notation` is incomplete diff --git a/tests/ui/async-await/return-type-notation/supertrait-bound.stderr b/tests/ui/async-await/return-type-notation/supertrait-bound.current.stderr index c8cec4946b4..05cb0ca4abd 100644 --- a/tests/ui/async-await/return-type-notation/supertrait-bound.stderr +++ b/tests/ui/async-await/return-type-notation/supertrait-bound.current.stderr @@ -1,5 +1,5 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/supertrait-bound.rs:3:49 + --> $DIR/supertrait-bound.rs:5:49 | LL | #![feature(return_position_impl_trait_in_trait, return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/return-type-notation/supertrait-bound.next.stderr b/tests/ui/async-await/return-type-notation/supertrait-bound.next.stderr new file mode 100644 index 00000000000..05cb0ca4abd --- /dev/null +++ b/tests/ui/async-await/return-type-notation/supertrait-bound.next.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/supertrait-bound.rs:5:49 + | +LL | #![feature(return_position_impl_trait_in_trait, return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/async-await/return-type-notation/supertrait-bound.rs b/tests/ui/async-await/return-type-notation/supertrait-bound.rs index 19bcfe3046b..09de32c5d4a 100644 --- a/tests/ui/async-await/return-type-notation/supertrait-bound.rs +++ b/tests/ui/async-await/return-type-notation/supertrait-bound.rs @@ -1,4 +1,6 @@ // check-pass +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(return_position_impl_trait_in_trait, return_type_notation)] //~^ WARN the feature `return_type_notation` is incomplete and may not be safe to use diff --git a/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr b/tests/ui/async-await/return-type-notation/ty-or-ct-params.current.stderr index 76928c5d7a3..1aa008fe469 100644 --- a/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr +++ b/tests/ui/async-await/return-type-notation/ty-or-ct-params.current.stderr @@ -1,5 +1,5 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/ty-or-ct-params.rs:3:31 + --> $DIR/ty-or-ct-params.rs:5:31 | LL | #![feature(async_fn_in_trait, return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #![feature(async_fn_in_trait, return_type_notation)] = note: `#[warn(incomplete_features)]` on by default error: return type notation is not allowed for functions that have type parameters - --> $DIR/ty-or-ct-params.rs:14:12 + --> $DIR/ty-or-ct-params.rs:16:12 | LL | async fn bar<T>() {} | - type parameter declared here @@ -17,7 +17,7 @@ LL | T: Foo<bar(): Send, baz(): Send>, | ^^^^^^^^^^^ error: return type notation is not allowed for functions that have const parameters - --> $DIR/ty-or-ct-params.rs:14:25 + --> $DIR/ty-or-ct-params.rs:16:25 | LL | async fn baz<const N: usize>() {} | -------------- const parameter declared here diff --git a/tests/ui/async-await/return-type-notation/ty-or-ct-params.next.stderr b/tests/ui/async-await/return-type-notation/ty-or-ct-params.next.stderr new file mode 100644 index 00000000000..1aa008fe469 --- /dev/null +++ b/tests/ui/async-await/return-type-notation/ty-or-ct-params.next.stderr @@ -0,0 +1,29 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/ty-or-ct-params.rs:5:31 + | +LL | #![feature(async_fn_in_trait, return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information + = note: `#[warn(incomplete_features)]` on by default + +error: return type notation is not allowed for functions that have type parameters + --> $DIR/ty-or-ct-params.rs:16:12 + | +LL | async fn bar<T>() {} + | - type parameter declared here +... +LL | T: Foo<bar(): Send, baz(): Send>, + | ^^^^^^^^^^^ + +error: return type notation is not allowed for functions that have const parameters + --> $DIR/ty-or-ct-params.rs:16:25 + | +LL | async fn baz<const N: usize>() {} + | -------------- const parameter declared here +... +LL | T: Foo<bar(): Send, baz(): Send>, + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors; 1 warning emitted + diff --git a/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs b/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs index 7871a2fed03..3141da1d296 100644 --- a/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs +++ b/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs @@ -1,4 +1,6 @@ // edition: 2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait, return_type_notation)] //~^ WARN the feature `return_type_notation` is incomplete diff --git a/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.rs b/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.rs new file mode 100644 index 00000000000..d8034d57e8d --- /dev/null +++ b/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.rs @@ -0,0 +1,40 @@ +use std::ops::Deref; +use std::rc::Rc; + +struct Value<T>(T); + +pub trait Wrap<T> { + fn wrap() -> Self; +} + +impl<R, A1, A2> Wrap<fn(A1, A2) -> R> for Value<fn(A1, A2) -> R> { + fn wrap() -> Self { + todo!() + } +} + +impl<F, R, A1, A2> Wrap<F> for Value<Rc<dyn Fn(A1, A2) -> R>> { + fn wrap() -> Self { + todo!() + } +} + +impl<F> Deref for Value<Rc<F>> { + type Target = F; + + fn deref(&self) -> &Self::Target { + &*self.0 + } +} + +fn main() { + let var_fn = Value::wrap(); + //~^ ERROR type annotations needed for `Value<Rc<_>>` + + // The combination of `Value: Wrap` obligation plus the autoderef steps + // (caused by the `Deref` impl above) actually means that the self type + // of the method fn below is constrained to be `Value<Rc<dyn Fn(?0, ?1) -> ?2>>`. + // However, that's only known to us on the error path -- we still need + // to emit an ambiguity error, though. + let _ = var_fn.clone(); +} diff --git a/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.stderr b/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.stderr new file mode 100644 index 00000000000..06a7e90858c --- /dev/null +++ b/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.stderr @@ -0,0 +1,17 @@ +error[E0282]: type annotations needed for `Value<Rc<_>>` + --> $DIR/deref-ambiguity-becomes-nonambiguous.rs:31:9 + | +LL | let var_fn = Value::wrap(); + | ^^^^^^ +... +LL | let _ = var_fn.clone(); + | ----- type must be known at this point + | +help: consider giving `var_fn` an explicit type, where the placeholders `_` are specified + | +LL | let var_fn: Value<Rc<_>> = Value::wrap(); + | ++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/chalkify/bugs/async.stderr b/tests/ui/chalkify/bugs/async.stderr index e6d46b02706..9ebaac31dcb 100644 --- a/tests/ui/chalkify/bugs/async.stderr +++ b/tests/ui/chalkify/bugs/async.stderr @@ -7,7 +7,7 @@ LL | async fn foo(x: u32) -> u32 { = help: the trait `Future` is not implemented for `[async fn body@$DIR/async.rs:23:29: 25:2]` = note: [async fn body@$DIR/async.rs:23:29: 25:2] must be a future or must implement `IntoFuture` to be awaited -error: internal compiler error: projection clauses should be implied from elsewhere. obligation: `Obligation(predicate=Binder(ProjectionPredicate(AliasTy { substs: [[async fn body@$DIR/async.rs:23:29: 25:2]], def_id: ... }, Term::Ty(u32)), []), depth=0)` +error: internal compiler error: projection clauses should be implied from elsewhere. obligation: `Obligation(predicate=Binder { value: ProjectionPredicate(AliasTy { substs: [[async fn body@$DIR/async.rs:23:29: 25:2]], def_id: ... }, Term::Ty(u32)), bound_vars: [] }, depth=0)` --> $DIR/async.rs:23:25 | LL | async fn foo(x: u32) -> u32 { diff --git a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs index 41b09ba0370..c3898afa967 100644 --- a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs +++ b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs @@ -87,6 +87,31 @@ fn test_4_should_not_capture_array() { } }; c(); + + // We also do not need to capture an array + // behind a reference (#112607) + let array: &[i32; 3] = &[0; 3]; + let c = #[rustc_capture_analysis] + || { + //~^ First Pass analysis includes: + match array { + [_, _, _] => {} + } + }; + c(); + + // We should still not insert a read if the array is inside an + // irrefutable pattern + struct Foo<T>(T); + let f = &Foo(&[10; 3]); + let c = #[rustc_capture_analysis] + || { + //~^ First Pass analysis includes: + match f { + Foo([_, _, _]) => () + } + }; + c(); } // Testing MultiVariant patterns diff --git a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.stderr b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.stderr index e137af1a0bd..c3c3f8b8477 100644 --- a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.stderr +++ b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.stderr @@ -109,7 +109,29 @@ LL | | }; | |_____^ error: First Pass analysis includes: - --> $DIR/patterns-capture-analysis.rs:105:5 + --> $DIR/patterns-capture-analysis.rs:95:5 + | +LL | / || { +LL | | +LL | | match array { +LL | | [_, _, _] => {} +LL | | } +LL | | }; + | |_____^ + +error: First Pass analysis includes: + --> $DIR/patterns-capture-analysis.rs:108:5 + | +LL | / || { +LL | | +LL | | match f { +LL | | Foo([_, _, _]) => () +LL | | } +LL | | }; + | |_____^ + +error: First Pass analysis includes: + --> $DIR/patterns-capture-analysis.rs:130:5 | LL | / || { LL | | @@ -121,13 +143,13 @@ LL | | }; | |_____^ | note: Capturing variant[] -> ImmBorrow - --> $DIR/patterns-capture-analysis.rs:108:15 + --> $DIR/patterns-capture-analysis.rs:133:15 | LL | match variant { | ^^^^^^^ error: Min Capture analysis includes: - --> $DIR/patterns-capture-analysis.rs:105:5 + --> $DIR/patterns-capture-analysis.rs:130:5 | LL | / || { LL | | @@ -139,13 +161,13 @@ LL | | }; | |_____^ | note: Min Capture variant[] -> ImmBorrow - --> $DIR/patterns-capture-analysis.rs:108:15 + --> $DIR/patterns-capture-analysis.rs:133:15 | LL | match variant { | ^^^^^^^ error: First Pass analysis includes: - --> $DIR/patterns-capture-analysis.rs:123:5 + --> $DIR/patterns-capture-analysis.rs:148:5 | LL | / || { LL | | @@ -157,13 +179,13 @@ LL | | }; | |_____^ | note: Capturing slice[] -> ImmBorrow - --> $DIR/patterns-capture-analysis.rs:126:15 + --> $DIR/patterns-capture-analysis.rs:151:15 | LL | match slice { | ^^^^^ error: Min Capture analysis includes: - --> $DIR/patterns-capture-analysis.rs:123:5 + --> $DIR/patterns-capture-analysis.rs:148:5 | LL | / || { LL | | @@ -175,13 +197,13 @@ LL | | }; | |_____^ | note: Min Capture slice[] -> ImmBorrow - --> $DIR/patterns-capture-analysis.rs:126:15 + --> $DIR/patterns-capture-analysis.rs:151:15 | LL | match slice { | ^^^^^ error: First Pass analysis includes: - --> $DIR/patterns-capture-analysis.rs:135:5 + --> $DIR/patterns-capture-analysis.rs:160:5 | LL | / || { LL | | @@ -193,13 +215,13 @@ LL | | }; | |_____^ | note: Capturing slice[] -> ImmBorrow - --> $DIR/patterns-capture-analysis.rs:138:15 + --> $DIR/patterns-capture-analysis.rs:163:15 | LL | match slice { | ^^^^^ error: Min Capture analysis includes: - --> $DIR/patterns-capture-analysis.rs:135:5 + --> $DIR/patterns-capture-analysis.rs:160:5 | LL | / || { LL | | @@ -211,13 +233,13 @@ LL | | }; | |_____^ | note: Min Capture slice[] -> ImmBorrow - --> $DIR/patterns-capture-analysis.rs:138:15 + --> $DIR/patterns-capture-analysis.rs:163:15 | LL | match slice { | ^^^^^ error: First Pass analysis includes: - --> $DIR/patterns-capture-analysis.rs:147:5 + --> $DIR/patterns-capture-analysis.rs:172:5 | LL | / || { LL | | @@ -229,13 +251,13 @@ LL | | }; | |_____^ | note: Capturing slice[] -> ImmBorrow - --> $DIR/patterns-capture-analysis.rs:150:15 + --> $DIR/patterns-capture-analysis.rs:175:15 | LL | match slice { | ^^^^^ error: Min Capture analysis includes: - --> $DIR/patterns-capture-analysis.rs:147:5 + --> $DIR/patterns-capture-analysis.rs:172:5 | LL | / || { LL | | @@ -247,13 +269,13 @@ LL | | }; | |_____^ | note: Min Capture slice[] -> ImmBorrow - --> $DIR/patterns-capture-analysis.rs:150:15 + --> $DIR/patterns-capture-analysis.rs:175:15 | LL | match slice { | ^^^^^ error: First Pass analysis includes: - --> $DIR/patterns-capture-analysis.rs:164:5 + --> $DIR/patterns-capture-analysis.rs:189:5 | LL | / || { LL | | @@ -264,5 +286,5 @@ LL | | } LL | | }; | |_____^ -error: aborting due to 16 previous errors +error: aborting due to 18 previous errors diff --git a/tests/ui/closures/cannot-call-unsized-via-ptr-2.rs b/tests/ui/closures/cannot-call-unsized-via-ptr-2.rs new file mode 100644 index 00000000000..2d8565517e8 --- /dev/null +++ b/tests/ui/closures/cannot-call-unsized-via-ptr-2.rs @@ -0,0 +1,11 @@ +#![feature(unsized_fn_params)] + +fn main() { + // CoerceMany "LUB" + let f = if true { |_a| {} } else { |_b| {} }; + //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time + //~| ERROR the size for values of type `[u8]` cannot be known at compilation time + + let slice: Box<[u8]> = Box::new([1; 8]); + f(*slice); +} diff --git a/tests/ui/closures/cannot-call-unsized-via-ptr-2.stderr b/tests/ui/closures/cannot-call-unsized-via-ptr-2.stderr new file mode 100644 index 00000000000..d88b84365df --- /dev/null +++ b/tests/ui/closures/cannot-call-unsized-via-ptr-2.stderr @@ -0,0 +1,21 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/cannot-call-unsized-via-ptr-2.rs:5:24 + | +LL | let f = if true { |_a| {} } else { |_b| {} }; + | ^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all function arguments must have a statically known size + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/cannot-call-unsized-via-ptr-2.rs:5:41 + | +LL | let f = if true { |_a| {} } else { |_b| {} }; + | ^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all function arguments must have a statically known size + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/closures/cannot-call-unsized-via-ptr.rs b/tests/ui/closures/cannot-call-unsized-via-ptr.rs new file mode 100644 index 00000000000..5ce4650b033 --- /dev/null +++ b/tests/ui/closures/cannot-call-unsized-via-ptr.rs @@ -0,0 +1,10 @@ +#![feature(unsized_fn_params)] + +fn main() { + // Simple coercion + let f: fn([u8]) = |_result| {}; + //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time + + let slice: Box<[u8]> = Box::new([1; 8]); + f(*slice); +} diff --git a/tests/ui/closures/cannot-call-unsized-via-ptr.stderr b/tests/ui/closures/cannot-call-unsized-via-ptr.stderr new file mode 100644 index 00000000000..9ecc66d5ce8 --- /dev/null +++ b/tests/ui/closures/cannot-call-unsized-via-ptr.stderr @@ -0,0 +1,12 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/cannot-call-unsized-via-ptr.rs:5:24 + | +LL | let f: fn([u8]) = |_result| {}; + | ^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all function arguments must have a statically known size + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/closures/closure-move-sync.rs b/tests/ui/closures/closure-move-sync.rs index ea2d1434c4a..3ee2b35f59f 100644 --- a/tests/ui/closures/closure-move-sync.rs +++ b/tests/ui/closures/closure-move-sync.rs @@ -13,10 +13,4 @@ fn bar() { t.join().unwrap(); } -fn foo() { - let (tx, _rx) = channel(); - thread::spawn(|| tx.send(()).unwrap()); - //~^ ERROR `Sender<()>` cannot be shared between threads safely -} - fn main() {} diff --git a/tests/ui/closures/closure-move-sync.stderr b/tests/ui/closures/closure-move-sync.stderr index 64e3b51ea71..aee903ac950 100644 --- a/tests/ui/closures/closure-move-sync.stderr +++ b/tests/ui/closures/closure-move-sync.stderr @@ -20,24 +20,6 @@ LL | let t = thread::spawn(|| { note: required by a bound in `spawn` --> $SRC_DIR/std/src/thread/mod.rs:LL:COL -error[E0277]: `Sender<()>` cannot be shared between threads safely - --> $DIR/closure-move-sync.rs:18:19 - | -LL | thread::spawn(|| tx.send(()).unwrap()); - | ------------- ^^^^^^^^^^^^^^^^^^^^^^^ `Sender<()>` cannot be shared between threads safely - | | - | required by a bound introduced by this call - | - = help: the trait `Sync` is not implemented for `Sender<()>` - = note: required for `&Sender<()>` to implement `Send` -note: required because it's used within this closure - --> $DIR/closure-move-sync.rs:18:19 - | -LL | thread::spawn(|| tx.send(()).unwrap()); - | ^^ -note: required by a bound in `spawn` - --> $SRC_DIR/std/src/thread/mod.rs:LL:COL - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/const-generics/issue-112505-overflow.stderr b/tests/ui/const-generics/issue-112505-overflow.stderr index 0432f2fa8be..bd8a4feeff5 100644 --- a/tests/ui/const-generics/issue-112505-overflow.stderr +++ b/tests/ui/const-generics/issue-112505-overflow.stderr @@ -4,8 +4,8 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^ | - = note: source type: `[[[u32; 8888888]; 9999999]; 777777777]` (values of the type `[[[u32; 8888888]; 9999999]; 777777777]` are too big for the current architecture) - = note: target type: `[[[u32; 9999999]; 777777777]; 239]` (59484438436515561504 bits) + = note: source type: `[[[u32; 8888888]; 9999999]; 777777777]` (values of the type `[[u32; 8888888]; 9999999]` are too big for the current architecture) + = note: target type: `[[[u32; 9999999]; 777777777]; 239]` (values of the type `[[u32; 9999999]; 777777777]` are too big for the current architecture) error: aborting due to previous error diff --git a/tests/ui/const-generics/transmute-fail.stderr b/tests/ui/const-generics/transmute-fail.stderr index 3d1197afd0f..9e308620a9c 100644 --- a/tests/ui/const-generics/transmute-fail.stderr +++ b/tests/ui/const-generics/transmute-fail.stderr @@ -43,8 +43,8 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ | - = note: source type: `[[[u32; 8888888]; 9999999]; 777777777]` (values of the type `[[[u32; 8888888]; 9999999]; 777777777]` are too big for the current architecture) - = note: target type: `[[[u32; 9999999]; 777777777]; 8888888]` (values of the type `[[[u32; 9999999]; 777777777]; 8888888]` are too big for the current architecture) + = note: source type: `[[[u32; 8888888]; 9999999]; 777777777]` (values of the type `[[u32; 8888888]; 9999999]` are too big for the current architecture) + = note: target type: `[[[u32; 9999999]; 777777777]; 8888888]` (values of the type `[[u32; 9999999]; 777777777]` are too big for the current architecture) error: aborting due to 6 previous errors diff --git a/tests/ui/consts/timeout.rs b/tests/ui/consts/timeout.rs new file mode 100644 index 00000000000..c9094999ee2 --- /dev/null +++ b/tests/ui/consts/timeout.rs @@ -0,0 +1,25 @@ +//! This test checks that external macros don't hide +//! the const eval timeout lint and then subsequently +//! ICE. + +// compile-flags: --crate-type=lib -Ztiny-const-eval-limit +// error-pattern: constant evaluation is taking a long time + +static ROOK_ATTACKS_TABLE: () = { + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); +}; diff --git a/tests/ui/consts/timeout.stderr b/tests/ui/consts/timeout.stderr new file mode 100644 index 00000000000..799b5ec8dd9 --- /dev/null +++ b/tests/ui/consts/timeout.stderr @@ -0,0 +1,15 @@ +error: constant evaluation is taking a long time + --> $SRC_DIR/core/src/num/mod.rs:LL:COL + | + = note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval. + If your compilation actually takes a long time, you can safely allow the lint. +help: the constant being evaluated + --> $DIR/timeout.rs:8:1 + | +LL | static ROOK_ATTACKS_TABLE: () = { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(long_running_const_eval)]` on by default + = note: this error originates in the macro `uint_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/tests/ui/enum/suggest-default-attribute.stderr b/tests/ui/enum/suggest-default-attribute.stderr index fb830d3f78b..b56d599a786 100644 --- a/tests/ui/enum/suggest-default-attribute.stderr +++ b/tests/ui/enum/suggest-default-attribute.stderr @@ -7,7 +7,7 @@ LL | #[default] help: consider adding a derive | LL + #[derive(Default)] -LL ~ pub enum Test { +LL | pub enum Test { | error: aborting due to previous error diff --git a/tests/ui/error-codes/E0283.stderr b/tests/ui/error-codes/E0283.stderr index 90316c6e981..89e634a7064 100644 --- a/tests/ui/error-codes/E0283.stderr +++ b/tests/ui/error-codes/E0283.stderr @@ -9,8 +9,8 @@ LL | let cont: u32 = Generator::create(); | help: use a fully-qualified path to a specific available implementation (2 found) | -LL | let cont: u32 = <Impl as Generator>::create(); - | ++++++++ + +LL | let cont: u32 = </* self type */ as Generator>::create(); + | +++++++++++++++++++ + error[E0283]: type annotations needed --> $DIR/E0283.rs:35:24 diff --git a/tests/ui/error-codes/E0790.stderr b/tests/ui/error-codes/E0790.stderr index fc025a3fca2..7248766285d 100644 --- a/tests/ui/error-codes/E0790.stderr +++ b/tests/ui/error-codes/E0790.stderr @@ -65,8 +65,8 @@ LL | MyTrait2::my_fn(); | help: use a fully-qualified path to a specific available implementation (2 found) | -LL | <Impl1 as MyTrait2>::my_fn(); - | +++++++++ + +LL | </* self type */ as MyTrait2>::my_fn(); + | +++++++++++++++++++ + error: aborting due to 5 previous errors diff --git a/tests/ui/extern/extern-crate-visibility.stderr b/tests/ui/extern/extern-crate-visibility.stderr index 9eeb83ae1a7..b239727092a 100644 --- a/tests/ui/extern/extern-crate-visibility.stderr +++ b/tests/ui/extern/extern-crate-visibility.stderr @@ -9,6 +9,10 @@ note: the crate import `core` is defined here | LL | extern crate core; | ^^^^^^^^^^^^^^^^^^ +help: consider importing this module instead + | +LL | use std::cell; + | ~~~~~~~~~ error[E0603]: crate import `core` is private --> $DIR/extern-crate-visibility.rs:9:10 @@ -21,6 +25,10 @@ note: the crate import `core` is defined here | LL | extern crate core; | ^^^^^^^^^^^^^^^^^^ +help: consider importing this struct instead + | +LL | std::cell::Cell::new(0); + | ~~~~~~~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/feature-gates/feature-gate-explicit_tail_calls.rs b/tests/ui/feature-gates/feature-gate-explicit_tail_calls.rs new file mode 100644 index 00000000000..856a7f39328 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-explicit_tail_calls.rs @@ -0,0 +1,9 @@ +pub fn you<T>() -> T { + become bottom(); //~ error: `become` expression is experimental +} + +pub fn bottom<T>() -> T { + become you(); //~ error: `become` expression is experimental +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-explicit_tail_calls.stderr b/tests/ui/feature-gates/feature-gate-explicit_tail_calls.stderr new file mode 100644 index 00000000000..b58da19c174 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-explicit_tail_calls.stderr @@ -0,0 +1,21 @@ +error[E0658]: `become` expression is experimental + --> $DIR/feature-gate-explicit_tail_calls.rs:2:5 + | +LL | become bottom(); + | ^^^^^^^^^^^^^^^ + | + = note: see issue #112788 <https://github.com/rust-lang/rust/issues/112788> for more information + = help: add `#![feature(explicit_tail_calls)]` to the crate attributes to enable + +error[E0658]: `become` expression is experimental + --> $DIR/feature-gate-explicit_tail_calls.rs:6:5 + | +LL | become you(); + | ^^^^^^^^^^^^ + | + = note: see issue #112788 <https://github.com/rust-lang/rust/issues/112788> for more information + = help: add `#![feature(explicit_tail_calls)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_current.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_current.stderr new file mode 100644 index 00000000000..ce39f6b2971 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_current.stderr @@ -0,0 +1,27 @@ +error[E0658]: return type notation is experimental + --> $DIR/feature-gate-return_type_notation.rs:17:17 + | +LL | fn foo<T: Trait<m(): Send>>() {} + | ^^^^^^^^^ + | + = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information + = help: add `#![feature(return_type_notation)]` to the crate attributes to enable + +error: parenthesized generic arguments cannot be used in associated type constraints + --> $DIR/feature-gate-return_type_notation.rs:17:17 + | +LL | fn foo<T: Trait<m(): Send>>() {} + | ^-- + | | + | help: remove these parentheses + +error[E0220]: associated type `m` not found for `Trait` + --> $DIR/feature-gate-return_type_notation.rs:17:17 + | +LL | fn foo<T: Trait<m(): Send>>() {} + | ^ associated type `m` not found + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0220, E0658. +For more information about an error, try `rustc --explain E0220`. diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_next.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_next.stderr new file mode 100644 index 00000000000..ce39f6b2971 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_next.stderr @@ -0,0 +1,27 @@ +error[E0658]: return type notation is experimental + --> $DIR/feature-gate-return_type_notation.rs:17:17 + | +LL | fn foo<T: Trait<m(): Send>>() {} + | ^^^^^^^^^ + | + = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information + = help: add `#![feature(return_type_notation)]` to the crate attributes to enable + +error: parenthesized generic arguments cannot be used in associated type constraints + --> $DIR/feature-gate-return_type_notation.rs:17:17 + | +LL | fn foo<T: Trait<m(): Send>>() {} + | ^-- + | | + | help: remove these parentheses + +error[E0220]: associated type `m` not found for `Trait` + --> $DIR/feature-gate-return_type_notation.rs:17:17 + | +LL | fn foo<T: Trait<m(): Send>>() {} + | ^ associated type `m` not found + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0220, E0658. +For more information about an error, try `rustc --explain E0220`. diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.no_current.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.no_current.stderr new file mode 100644 index 00000000000..d11359e7f48 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.no_current.stderr @@ -0,0 +1,13 @@ +warning: return type notation is experimental + --> $DIR/feature-gate-return_type_notation.rs:17:17 + | +LL | fn foo<T: Trait<m(): Send>>() {} + | ^^^^^^^^^ + | + = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information + = help: add `#![feature(return_type_notation)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860> + +warning: 1 warning emitted + diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.no_next.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.no_next.stderr new file mode 100644 index 00000000000..d11359e7f48 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.no_next.stderr @@ -0,0 +1,13 @@ +warning: return type notation is experimental + --> $DIR/feature-gate-return_type_notation.rs:17:17 + | +LL | fn foo<T: Trait<m(): Send>>() {} + | ^^^^^^^^^ + | + = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information + = help: add `#![feature(return_type_notation)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860> + +warning: 1 warning emitted + diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.rs b/tests/ui/feature-gates/feature-gate-return_type_notation.rs index d9bcb65feba..7e8c1eb95ca 100644 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.rs +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.rs @@ -1,7 +1,10 @@ // edition: 2021 -// revisions: cfg no +// revisions: cfg_current cfg_next no_current no_next +// [cfg_next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// [no_next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty -//[no] check-pass +// [no_current] check-pass +// [no_next] check-pass // Since we're not adding new syntax, `cfg`'d out RTN must pass. #![feature(async_fn_in_trait)] @@ -10,12 +13,17 @@ trait Trait { async fn m(); } -#[cfg(cfg)] +#[cfg(any(cfg_current, cfg_next))] fn foo<T: Trait<m(): Send>>() {} -//[cfg]~^ ERROR return type notation is experimental -//[cfg]~| ERROR parenthesized generic arguments cannot be used in associated type constraints -//[cfg]~| ERROR associated type `m` not found for `Trait` -//[no]~^^^^ WARN return type notation is experimental -//[no]~| WARN unstable syntax can change at any point in the future, causing a hard error! +//[cfg_current]~^ ERROR return type notation is experimental +//[cfg_current]~| ERROR parenthesized generic arguments cannot be used in associated type constraints +//[cfg_current]~| ERROR associated type `m` not found for `Trait` +//[cfg_next]~^^^^ ERROR return type notation is experimental +//[cfg_next]~| ERROR parenthesized generic arguments cannot be used in associated type constraints +//[cfg_next]~| ERROR associated type `m` not found for `Trait` +//[no_current]~^^^^^^^ WARN return type notation is experimental +//[no_current]~| WARN unstable syntax can change at any point in the future, causing a hard error! +//[no_next]~^^^^^^^^^ WARN return type notation is experimental +//[no_next]~| WARN unstable syntax can change at any point in the future, causing a hard error! fn main() {} diff --git a/tests/ui/for/issue-20605.next.stderr b/tests/ui/for/issue-20605.next.stderr index 5362a68c834..a96a53ca93e 100644 --- a/tests/ui/for/issue-20605.next.stderr +++ b/tests/ui/for/issue-20605.next.stderr @@ -14,7 +14,7 @@ LL | for item in *things { *item = 0 } = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature -error: the type `<_ as IntoIterator>::IntoIter` is not well-formed +error: the type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed --> $DIR/issue-20605.rs:5:17 | LL | for item in *things { *item = 0 } diff --git a/tests/ui/for/issue-20605.rs b/tests/ui/for/issue-20605.rs index 499271fa92f..64156b35705 100644 --- a/tests/ui/for/issue-20605.rs +++ b/tests/ui/for/issue-20605.rs @@ -4,7 +4,7 @@ fn changer<'a>(mut things: Box<dyn Iterator<Item=&'a mut u8>>) { for item in *things { *item = 0 } //~^ ERROR the size for values of type - //[next]~^^ ERROR the type `<_ as IntoIterator>::IntoIter` is not well-formed + //[next]~^^ ERROR the type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed //[next]~| ERROR the trait bound `dyn Iterator<Item = &'a mut u8>: IntoIterator` is not satisfied } diff --git a/tests/ui/generic-associated-types/issue-88595.rs b/tests/ui/generic-associated-types/issue-88595.rs index 7de906e7ef3..5a40a612972 100644 --- a/tests/ui/generic-associated-types/issue-88595.rs +++ b/tests/ui/generic-associated-types/issue-88595.rs @@ -19,5 +19,4 @@ impl<'a> A<'a> for C { type B<'b> = impl Clone; fn a(&'a self) -> Self::B<'a> {} //~ ERROR: non-defining opaque type use in defining scope - //~^ ERROR: mismatched types } diff --git a/tests/ui/generic-associated-types/issue-88595.stderr b/tests/ui/generic-associated-types/issue-88595.stderr index d6caed85459..2b1a25acfa4 100644 --- a/tests/ui/generic-associated-types/issue-88595.stderr +++ b/tests/ui/generic-associated-types/issue-88595.stderr @@ -1,8 +1,8 @@ error: non-defining opaque type use in defining scope - --> $DIR/issue-88595.rs:21:5 + --> $DIR/issue-88595.rs:21:23 | LL | fn a(&'a self) -> Self::B<'a> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ generic argument `'a` used twice + | ^^^^^^^^^^^ generic argument `'a` used twice | note: for this opaque type --> $DIR/issue-88595.rs:19:18 @@ -10,25 +10,5 @@ note: for this opaque type LL | type B<'b> = impl Clone; | ^^^^^^^^^^ -error[E0308]: mismatched types - --> $DIR/issue-88595.rs:21:23 - | -LL | type B<'b> = impl Clone; - | ---------- the expected opaque type -LL | -LL | fn a(&'a self) -> Self::B<'a> {} - | - ^^^^^^^^^^^ expected opaque type, found `()` - | | - | implicitly returns `()` as its body has no tail or `return` expression - | - = note: expected opaque type `<C as A<'a>>::B<'a>` - found unit type `()` -note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/issue-88595.rs:21:5 - | -LL | fn a(&'a self) -> Self::B<'a> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/coherence-treats-tait-ambig.current.stderr b/tests/ui/impl-trait/coherence-treats-tait-ambig.current.stderr new file mode 100644 index 00000000000..61fed16294b --- /dev/null +++ b/tests/ui/impl-trait/coherence-treats-tait-ambig.current.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `Into<T>` for type `Foo` + --> $DIR/coherence-treats-tait-ambig.rs:10:1 + | +LL | impl Into<T> for Foo { + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl<T, U> Into<U> for T + where U: From<T>; + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/impl-trait/coherence-treats-tait-ambig.next.stderr b/tests/ui/impl-trait/coherence-treats-tait-ambig.next.stderr new file mode 100644 index 00000000000..61fed16294b --- /dev/null +++ b/tests/ui/impl-trait/coherence-treats-tait-ambig.next.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `Into<T>` for type `Foo` + --> $DIR/coherence-treats-tait-ambig.rs:10:1 + | +LL | impl Into<T> for Foo { + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl<T, U> Into<U> for T + where U: From<T>; + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/impl-trait/coherence-treats-tait-ambig.rs b/tests/ui/impl-trait/coherence-treats-tait-ambig.rs new file mode 100644 index 00000000000..156a7eb0e23 --- /dev/null +++ b/tests/ui/impl-trait/coherence-treats-tait-ambig.rs @@ -0,0 +1,19 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + +#![feature(type_alias_impl_trait)] + +type T = impl Sized; + +struct Foo; + +impl Into<T> for Foo { +//~^ ERROR conflicting implementations of trait `Into<T>` for type `Foo` + fn into(self) -> T { + Foo + } +} + +fn main() { + let _: T = Foo.into(); +} diff --git a/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr b/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr index 1097cd0f452..8e61a65abe4 100644 --- a/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr +++ b/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr @@ -40,10 +40,10 @@ LL | fn method() -> Self::Ty; = note: expected signature `fn() -> <() as compare_method::Trait>::Ty` found signature `fn()` note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/in-assoc-type-unconstrained.rs:22:9 + --> $DIR/in-assoc-type-unconstrained.rs:22:12 | LL | fn method() -> () {} - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^ error: unconstrained opaque type --> $DIR/in-assoc-type-unconstrained.rs:20:19 diff --git a/tests/ui/impl-trait/in-assoc-type.stderr b/tests/ui/impl-trait/in-assoc-type.stderr index f0a272dc2d5..ab3f3a14410 100644 --- a/tests/ui/impl-trait/in-assoc-type.stderr +++ b/tests/ui/impl-trait/in-assoc-type.stderr @@ -12,10 +12,10 @@ LL | fn foo(&self) -> <Self as Foo<()>>::Bar {} = note: expected opaque type `<() as Foo<()>>::Bar` found unit type `()` note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/in-assoc-type.rs:17:5 + --> $DIR/in-assoc-type.rs:17:8 | LL | fn foo(&self) -> <Self as Foo<()>>::Bar {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^ error: aborting due to previous error diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed b/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed new file mode 100644 index 00000000000..d9f775a6c84 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed @@ -0,0 +1,25 @@ +// edition:2021 +// run-rustfix + +#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] + +trait Trait { + async fn foo(); + + async fn bar() -> i32; + + fn test(&self) -> impl Sized + '_; + + async fn baz(&self) -> &i32; +} + +struct S; + +impl Trait for S {async fn baz(&self) -> &i32 { todo!() } +fn test(&self) -> impl Sized + '_ { todo!() } +async fn bar() -> i32 { todo!() } +async fn foo() { todo!() } +} +//~^ ERROR not all trait items implemented + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.rs b/tests/ui/impl-trait/in-trait/suggest-missing-item.rs new file mode 100644 index 00000000000..26979b5149b --- /dev/null +++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.rs @@ -0,0 +1,21 @@ +// edition:2021 +// run-rustfix + +#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] + +trait Trait { + async fn foo(); + + async fn bar() -> i32; + + fn test(&self) -> impl Sized + '_; + + async fn baz(&self) -> &i32; +} + +struct S; + +impl Trait for S {} +//~^ ERROR not all trait items implemented + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr b/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr new file mode 100644 index 00000000000..44f98896eb3 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr @@ -0,0 +1,21 @@ +error[E0046]: not all trait items implemented, missing: `foo`, `bar`, `test`, `baz` + --> $DIR/suggest-missing-item.rs:18:1 + | +LL | async fn foo(); + | --------------- `foo` from trait +LL | +LL | async fn bar() -> i32; + | ---------------------- `bar` from trait +LL | +LL | fn test(&self) -> impl Sized + '_; + | ---------------------------------- `test` from trait +LL | +LL | async fn baz(&self) -> &i32; + | ---------------------------- `baz` from trait +... +LL | impl Trait for S {} + | ^^^^^^^^^^^^^^^^ missing `foo`, `bar`, `test`, `baz` in implementation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0046`. diff --git a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr index bbd60d4398b..fe765271bd2 100644 --- a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr +++ b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr @@ -20,11 +20,6 @@ LL | fn eq(&self, _other: &(Foo, i32)) -> bool { | = note: expected signature `fn(&a::Bar, &(a::Bar, i32)) -> _` found signature `fn(&a::Bar, &(a::Foo, i32)) -> _` -note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:10:9 - | -LL | fn eq(&self, _other: &(Foo, i32)) -> bool { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unconstrained opaque type --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:18:16 @@ -49,10 +44,10 @@ LL | fn eq(&self, _other: &(Bar, i32)) -> bool { = note: expected signature `fn(&b::Bar, &(b::Foo, i32)) -> _` found signature `fn(&b::Bar, &(b::Bar, i32)) -> _` note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:24:9 + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:24:12 | LL | fn eq(&self, _other: &(Bar, i32)) -> bool { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ error: aborting due to 4 previous errors diff --git a/tests/ui/issues/issue-11680.stderr b/tests/ui/issues/issue-11680.stderr index ea224af8ed7..5bcf93de811 100644 --- a/tests/ui/issues/issue-11680.stderr +++ b/tests/ui/issues/issue-11680.stderr @@ -2,7 +2,9 @@ error[E0603]: enum `Foo` is private --> $DIR/issue-11680.rs:6:21 | LL | let _b = other::Foo::Bar(1); - | ^^^ private enum + | ^^^ --- tuple variant `Bar` is not publicly re-exported + | | + | private enum | note: the enum `Foo` is defined here --> $DIR/auxiliary/issue-11680.rs:1:1 @@ -14,7 +16,9 @@ error[E0603]: enum `Foo` is private --> $DIR/issue-11680.rs:9:27 | LL | let _b = other::test::Foo::Bar(1); - | ^^^ private enum + | ^^^ --- tuple variant `Bar` is not publicly re-exported + | | + | private enum | note: the enum `Foo` is defined here --> $DIR/auxiliary/issue-11680.rs:6:5 diff --git a/tests/ui/issues/issue-5883.rs b/tests/ui/issues/issue-5883.rs index 82866b35557..f9dd2c54d99 100644 --- a/tests/ui/issues/issue-5883.rs +++ b/tests/ui/issues/issue-5883.rs @@ -6,7 +6,7 @@ struct Struct { fn new_struct( r: dyn A + 'static //~ ERROR the size for values of type -) -> Struct { //~ ERROR the size for values of type +) -> Struct { Struct { r: r } } diff --git a/tests/ui/issues/issue-5883.stderr b/tests/ui/issues/issue-5883.stderr index ffff403e0d4..a3e2531b5ca 100644 --- a/tests/ui/issues/issue-5883.stderr +++ b/tests/ui/issues/issue-5883.stderr @@ -15,22 +15,6 @@ help: function arguments must have a statically known size, borrowed types alway LL | r: &dyn A + 'static | + -error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time - --> $DIR/issue-5883.rs:9:6 - | -LL | ) -> Struct { - | ^^^^^^ doesn't have a size known at compile-time -LL | Struct { r: r } - | --------------- this returned value is of type `Struct` - | - = help: within `Struct`, the trait `Sized` is not implemented for `(dyn A + 'static)` -note: required because it appears within the type `Struct` - --> $DIR/issue-5883.rs:3:8 - | -LL | struct Struct { - | ^^^^^^ - = note: the return type of a function must have a statically known size - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/layout/cannot-transmute-unnormalizable-type.rs b/tests/ui/layout/cannot-transmute-unnormalizable-type.rs new file mode 100644 index 00000000000..d2b6e1d8eba --- /dev/null +++ b/tests/ui/layout/cannot-transmute-unnormalizable-type.rs @@ -0,0 +1,22 @@ +trait Trait { + type RefTarget; +} + +impl Trait for () +where + Missing: Trait, + //~^ ERROR cannot find type `Missing` in this scope +{ + type RefTarget = (); +} + +struct Other { + data: <() as Trait>::RefTarget, +} + +fn main() { + unsafe { + std::mem::transmute::<Option<()>, Option<&Other>>(None); + //~^ ERROR cannot transmute between types of different sizes, or dependently-sized types + } +} diff --git a/tests/ui/layout/cannot-transmute-unnormalizable-type.stderr b/tests/ui/layout/cannot-transmute-unnormalizable-type.stderr new file mode 100644 index 00000000000..dd5119318ff --- /dev/null +++ b/tests/ui/layout/cannot-transmute-unnormalizable-type.stderr @@ -0,0 +1,19 @@ +error[E0412]: cannot find type `Missing` in this scope + --> $DIR/cannot-transmute-unnormalizable-type.rs:7:5 + | +LL | Missing: Trait, + | ^^^^^^^ not found in this scope + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/cannot-transmute-unnormalizable-type.rs:19:9 + | +LL | std::mem::transmute::<Option<()>, Option<&Other>>(None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `Option<()>` (8 bits) + = note: target type: `Option<&Other>` (unable to determine layout for `Other` because `<() as Trait>::RefTarget` cannot be normalized) + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0412, E0512. +For more information about an error, try `rustc --explain E0412`. diff --git a/tests/ui/macros/issue-88228.stderr b/tests/ui/macros/issue-88228.stderr index 1dbe2b77be2..f9d0ac95da7 100644 --- a/tests/ui/macros/issue-88228.stderr +++ b/tests/ui/macros/issue-88228.stderr @@ -4,7 +4,7 @@ error: cannot find macro `bla` in this scope LL | bla!(); | ^^^ | -help: consider importing this macro +help: consider importing this macro through its public re-export | LL + use crate::hey::bla; | @@ -23,7 +23,7 @@ error: cannot find derive macro `Bla` in this scope LL | #[derive(Bla)] | ^^^ | -help: consider importing this derive macro +help: consider importing this derive macro through its public re-export | LL + use crate::hey::Bla; | diff --git a/tests/ui/nll/ty-outlives/impl-trait-captures.stderr b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr index da4b9595c0e..ba885d1b97e 100644 --- a/tests/ui/nll/ty-outlives/impl-trait-captures.stderr +++ b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr @@ -1,4 +1,4 @@ -error[E0700]: hidden type for `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [ReEarlyBound(0, 'a), T, ReEarlyBound(0, 'a)])` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [ReEarlyBound(DefId(0:9 ~ impl_trait_captures[aeb9]::foo::'a), 0, 'a), T, ReEarlyBound(DefId(0:9 ~ impl_trait_captures[aeb9]::foo::'a), 0, 'a)])` captures lifetime that does not appear in bounds --> $DIR/impl-trait-captures.rs:11:5 | LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> { @@ -8,7 +8,7 @@ LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> { LL | x | ^ | -help: to declare that `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [ReEarlyBound(0, 'a), T, ReEarlyBound(2, 'a)])` captures `ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))` lifetime bound +help: to declare that `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [ReEarlyBound(DefId(0:9 ~ impl_trait_captures[aeb9]::foo::'a), 0, 'a), T, ReEarlyBound(DefId(0:14 ~ impl_trait_captures[aeb9]::foo::{opaque#0}::'a), 2, 'a)])` captures `ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))` lifetime bound | LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_)) { | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/tests/ui/offset-of/offset-of-dst-field.stderr b/tests/ui/offset-of/offset-of-dst-field.stderr index 3f613d947e4..658678dc4ed 100644 --- a/tests/ui/offset-of/offset-of-dst-field.stderr +++ b/tests/ui/offset-of/offset-of-dst-field.stderr @@ -34,6 +34,20 @@ LL | offset_of!((u8, dyn Trait), 1); = help: the trait `Sized` is not implemented for `dyn Trait` = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/offset-of-dst-field.rs:44:5 + | +LL | offset_of!(Delta<Alpha>, z); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `Alpha`, the trait `Sized` is not implemented for `[u8]` +note: required because it appears within the type `Alpha` + --> $DIR/offset-of-dst-field.rs:5:8 + | +LL | struct Alpha { + | ^^^^^ + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0277]: the size for values of type `Extern` cannot be known at compilation time --> $DIR/offset-of-dst-field.rs:45:5 | @@ -52,20 +66,6 @@ LL | offset_of!(Delta<dyn Trait>, z); = help: the trait `Sized` is not implemented for `dyn Trait` = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/offset-of-dst-field.rs:44:5 - | -LL | offset_of!(Delta<Alpha>, z); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: within `Alpha`, the trait `Sized` is not implemented for `[u8]` -note: required because it appears within the type `Alpha` - --> $DIR/offset-of-dst-field.rs:5:8 - | -LL | struct Alpha { - | ^^^^^ - = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/offset-of-dst-field.rs:50:5 | diff --git a/tests/ui/offset-of/offset-of-must-use.rs b/tests/ui/offset-of/offset-of-must-use.rs new file mode 100644 index 00000000000..e30145d7a2f --- /dev/null +++ b/tests/ui/offset-of/offset-of-must-use.rs @@ -0,0 +1,9 @@ +// check-pass + +#![feature(offset_of)] +#![warn(unused)] + +fn main() { + core::mem::offset_of!((String,), 0); + //~^ WARN unused return value of `must_use` that must be used +} diff --git a/tests/ui/offset-of/offset-of-must-use.stderr b/tests/ui/offset-of/offset-of-must-use.stderr new file mode 100644 index 00000000000..5fe387a7255 --- /dev/null +++ b/tests/ui/offset-of/offset-of-must-use.stderr @@ -0,0 +1,16 @@ +warning: unused return value of `must_use` that must be used + --> $DIR/offset-of-must-use.rs:7:5 + | +LL | core::mem::offset_of!((String,), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/offset-of-must-use.rs:4:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_must_use)]` implied by `#[warn(unused)]` + = note: this warning originates in the macro `core::mem::offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 1 warning emitted + diff --git a/tests/ui/offset-of/offset-of-output-type.stderr b/tests/ui/offset-of/offset-of-output-type.stderr index 6f8c9475029..6133f3263ab 100644 --- a/tests/ui/offset-of/offset-of-output-type.stderr +++ b/tests/ui/offset-of/offset-of-output-type.stderr @@ -2,9 +2,7 @@ error[E0308]: mismatched types --> $DIR/offset-of-output-type.rs:12:17 | LL | let _: u8 = offset_of!(S, v); - | -- ^^^^^^^^^^^^^^^^ expected `u8`, found `usize` - | | - | expected due to this + | ^^^^^^^^^^^^^^^^ expected `u8`, found `usize` | = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -12,9 +10,7 @@ error[E0308]: mismatched types --> $DIR/offset-of-output-type.rs:13:18 | LL | let _: u16 = offset_of!(S, v); - | --- ^^^^^^^^^^^^^^^^ expected `u16`, found `usize` - | | - | expected due to this + | ^^^^^^^^^^^^^^^^ expected `u16`, found `usize` | = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -22,9 +18,7 @@ error[E0308]: mismatched types --> $DIR/offset-of-output-type.rs:14:18 | LL | let _: u32 = offset_of!(S, v); - | --- ^^^^^^^^^^^^^^^^ expected `u32`, found `usize` - | | - | expected due to this + | ^^^^^^^^^^^^^^^^ expected `u32`, found `usize` | = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -32,9 +26,7 @@ error[E0308]: mismatched types --> $DIR/offset-of-output-type.rs:15:18 | LL | let _: u64 = offset_of!(S, v); - | --- ^^^^^^^^^^^^^^^^ expected `u64`, found `usize` - | | - | expected due to this + | ^^^^^^^^^^^^^^^^ expected `u64`, found `usize` | = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -42,9 +34,7 @@ error[E0308]: mismatched types --> $DIR/offset-of-output-type.rs:16:20 | LL | let _: isize = offset_of!(S, v); - | ----- ^^^^^^^^^^^^^^^^ expected `isize`, found `usize` - | | - | expected due to this + | ^^^^^^^^^^^^^^^^ expected `isize`, found `usize` | = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/offset-of/offset-of-tuple.stderr b/tests/ui/offset-of/offset-of-tuple.stderr index 954515f80a6..ed952345806 100644 --- a/tests/ui/offset-of/offset-of-tuple.stderr +++ b/tests/ui/offset-of/offset-of-tuple.stderr @@ -90,10 +90,7 @@ error: expected identifier, found `)` --> $DIR/offset-of-tuple.rs:14:5 | LL | offset_of!((u8, u8), 1.); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | expected identifier - | in this macro invocation + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected identifier | = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -110,10 +107,7 @@ error: expected identifier, found `)` --> $DIR/offset-of-tuple.rs:36:5 | LL | offset_of!(ComplexTup, 0.0.1.); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | expected identifier - | in this macro invocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected identifier | = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -147,10 +141,7 @@ error: expected identifier, found `)` --> $DIR/offset-of-tuple.rs:40:5 | LL | offset_of!(ComplexTup, 0.0 .1.); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | expected identifier - | in this macro invocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected identifier | = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -158,10 +149,7 @@ error: expected identifier, found `)` --> $DIR/offset-of-tuple.rs:41:5 | LL | offset_of!(ComplexTup, 0.0 . 1.); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | expected identifier - | in this macro invocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected identifier | = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -169,10 +157,7 @@ error: expected identifier, found `)` --> $DIR/offset-of-tuple.rs:42:5 | LL | offset_of!(ComplexTup, 0.0. 1.); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | expected identifier - | in this macro invocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected identifier | = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/privacy/export-tag-variant.stderr b/tests/ui/privacy/export-tag-variant.stderr index f73bd454d35..e8906985e05 100644 --- a/tests/ui/privacy/export-tag-variant.stderr +++ b/tests/ui/privacy/export-tag-variant.stderr @@ -2,7 +2,9 @@ error[E0603]: enum `Y` is private --> $DIR/export-tag-variant.rs:7:26 | LL | fn main() { let z = foo::Y::Y1; } - | ^ private enum + | ^ -- unit variant `Y1` is not publicly re-exported + | | + | private enum | note: the enum `Y` is defined here --> $DIR/export-tag-variant.rs:4:5 diff --git a/tests/ui/privacy/privacy-in-paths.stderr b/tests/ui/privacy/privacy-in-paths.stderr index 2eb3ebb51c2..9c3d5e97c62 100644 --- a/tests/ui/privacy/privacy-in-paths.stderr +++ b/tests/ui/privacy/privacy-in-paths.stderr @@ -2,7 +2,9 @@ error[E0603]: module `bar` is private --> $DIR/privacy-in-paths.rs:24:16 | LL | ::foo::bar::baz::f(); - | ^^^ private module + | ^^^ - function `f` is not publicly re-exported + | | + | private module | note: the module `bar` is defined here --> $DIR/privacy-in-paths.rs:3:5 @@ -21,12 +23,18 @@ note: the module `bar` is defined here | LL | mod bar { | ^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL | foo::S::f(); + | ~~~~~~ error[E0603]: trait `T` is private --> $DIR/privacy-in-paths.rs:26:23 | LL | <() as ::foo::T>::Assoc::f(); - | ^ private trait + | ^ ----- associated type `Assoc` is not publicly re-exported + | | + | private trait | note: the trait `T` is defined here --> $DIR/privacy-in-paths.rs:8:5 diff --git a/tests/ui/privacy/privacy-ufcs.stderr b/tests/ui/privacy/privacy-ufcs.stderr index e93a458ce6c..f45f3d8ec37 100644 --- a/tests/ui/privacy/privacy-ufcs.stderr +++ b/tests/ui/privacy/privacy-ufcs.stderr @@ -2,7 +2,9 @@ error[E0603]: trait `Bar` is private --> $DIR/privacy-ufcs.rs:12:20 | LL | <i32 as ::foo::Bar>::baz(); - | ^^^ private trait + | ^^^ --- associated function `baz` is not publicly re-exported + | | + | private trait | note: the trait `Bar` is defined here --> $DIR/privacy-ufcs.rs:4:5 diff --git a/tests/ui/privacy/privacy1.stderr b/tests/ui/privacy/privacy1.stderr index 6ebed8ee062..ca8f242e0be 100644 --- a/tests/ui/privacy/privacy1.stderr +++ b/tests/ui/privacy/privacy1.stderr @@ -50,7 +50,9 @@ error[E0603]: module `baz` is private --> $DIR/privacy1.rs:104:16 | LL | ::bar::baz::A::foo(); - | ^^^ private module + | ^^^ - struct `A` is not publicly re-exported + | | + | private module | note: the module `baz` is defined here --> $DIR/privacy1.rs:50:5 @@ -62,7 +64,9 @@ error[E0603]: module `baz` is private --> $DIR/privacy1.rs:105:16 | LL | ::bar::baz::A::bar(); - | ^^^ private module + | ^^^ - struct `A` is not publicly re-exported + | | + | private module | note: the module `baz` is defined here --> $DIR/privacy1.rs:50:5 @@ -74,7 +78,9 @@ error[E0603]: module `baz` is private --> $DIR/privacy1.rs:107:16 | LL | ::bar::baz::A.foo2(); - | ^^^ private module + | ^^^ - unit struct `A` is not publicly re-exported + | | + | private module | note: the module `baz` is defined here --> $DIR/privacy1.rs:50:5 @@ -86,7 +92,9 @@ error[E0603]: module `baz` is private --> $DIR/privacy1.rs:108:16 | LL | ::bar::baz::A.bar2(); - | ^^^ private module + | ^^^ - unit struct `A` is not publicly re-exported + | | + | private module | note: the module `baz` is defined here --> $DIR/privacy1.rs:50:5 @@ -98,7 +106,9 @@ error[E0603]: trait `B` is private --> $DIR/privacy1.rs:112:16 | LL | ::bar::B::foo(); - | ^ private trait + | ^ --- associated function `foo` is not publicly re-exported + | | + | private trait | note: the trait `B` is defined here --> $DIR/privacy1.rs:40:5 @@ -129,6 +139,10 @@ note: the module `baz` is defined here | LL | mod baz { | ^^^^^^^ +help: consider importing this function through its public re-export instead + | +LL | bar::foo(); + | ~~~~~~~~ error[E0603]: module `baz` is private --> $DIR/privacy1.rs:128:16 @@ -141,6 +155,10 @@ note: the module `baz` is defined here | LL | mod baz { | ^^^^^^^ +help: consider importing this function through its public re-export instead + | +LL | bar::bar(); + | ~~~~~~~~ error[E0603]: trait `B` is private --> $DIR/privacy1.rs:157:17 diff --git a/tests/ui/privacy/sealed-traits/private-trait-non-local.rs b/tests/ui/privacy/sealed-traits/private-trait-non-local.rs new file mode 100644 index 00000000000..426f21cc7de --- /dev/null +++ b/tests/ui/privacy/sealed-traits/private-trait-non-local.rs @@ -0,0 +1,4 @@ +extern crate core; +use core::slice::index::private_slice_index::Sealed; //~ ERROR module `index` is private +fn main() { +} diff --git a/tests/ui/privacy/sealed-traits/private-trait-non-local.stderr b/tests/ui/privacy/sealed-traits/private-trait-non-local.stderr new file mode 100644 index 00000000000..29499979866 --- /dev/null +++ b/tests/ui/privacy/sealed-traits/private-trait-non-local.stderr @@ -0,0 +1,12 @@ +error[E0603]: module `index` is private + --> $DIR/private-trait-non-local.rs:2:18 + | +LL | use core::slice::index::private_slice_index::Sealed; + | ^^^^^ private module ------ trait `Sealed` is not publicly re-exported + | +note: the module `index` is defined here + --> $SRC_DIR/core/src/slice/mod.rs:LL:COL + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/privacy/sealed-traits/private-trait.rs b/tests/ui/privacy/sealed-traits/private-trait.rs new file mode 100644 index 00000000000..bbcbaabfaf4 --- /dev/null +++ b/tests/ui/privacy/sealed-traits/private-trait.rs @@ -0,0 +1,10 @@ +pub mod a { + mod b { + pub trait Hidden {} + } +} + +struct S; +impl a::b::Hidden for S {} //~ ERROR module `b` is private + +fn main() {} diff --git a/tests/ui/privacy/sealed-traits/private-trait.stderr b/tests/ui/privacy/sealed-traits/private-trait.stderr new file mode 100644 index 00000000000..c7ec72ff166 --- /dev/null +++ b/tests/ui/privacy/sealed-traits/private-trait.stderr @@ -0,0 +1,17 @@ +error[E0603]: module `b` is private + --> $DIR/private-trait.rs:8:9 + | +LL | impl a::b::Hidden for S {} + | ^ ------ trait `Hidden` is not publicly re-exported + | | + | private module + | +note: the module `b` is defined here + --> $DIR/private-trait.rs:2:5 + | +LL | mod b { + | ^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/privacy/sealed-traits/re-exported-trait.fixed b/tests/ui/privacy/sealed-traits/re-exported-trait.fixed new file mode 100644 index 00000000000..79b6a6516ab --- /dev/null +++ b/tests/ui/privacy/sealed-traits/re-exported-trait.fixed @@ -0,0 +1,13 @@ +// run-rustfix + +pub mod a { + pub use self::b::Trait; + mod b { + pub trait Trait {} + } +} + +struct S; +impl a::Trait for S {} //~ ERROR module `b` is private + +fn main() {} diff --git a/tests/ui/privacy/sealed-traits/re-exported-trait.rs b/tests/ui/privacy/sealed-traits/re-exported-trait.rs new file mode 100644 index 00000000000..5f96dfdcbd6 --- /dev/null +++ b/tests/ui/privacy/sealed-traits/re-exported-trait.rs @@ -0,0 +1,13 @@ +// run-rustfix + +pub mod a { + pub use self::b::Trait; + mod b { + pub trait Trait {} + } +} + +struct S; +impl a::b::Trait for S {} //~ ERROR module `b` is private + +fn main() {} diff --git a/tests/ui/privacy/sealed-traits/re-exported-trait.stderr b/tests/ui/privacy/sealed-traits/re-exported-trait.stderr new file mode 100644 index 00000000000..b630565d023 --- /dev/null +++ b/tests/ui/privacy/sealed-traits/re-exported-trait.stderr @@ -0,0 +1,19 @@ +error[E0603]: module `b` is private + --> $DIR/re-exported-trait.rs:11:9 + | +LL | impl a::b::Trait for S {} + | ^ private module + | +note: the module `b` is defined here + --> $DIR/re-exported-trait.rs:5:5 + | +LL | mod b { + | ^^^^^ +help: consider importing this trait through its public re-export instead + | +LL | impl a::Trait for S {} + | ~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/privacy/sealed-traits/sealed-trait-local.rs b/tests/ui/privacy/sealed-traits/sealed-trait-local.rs new file mode 100644 index 00000000000..778ddf0f817 --- /dev/null +++ b/tests/ui/privacy/sealed-traits/sealed-trait-local.rs @@ -0,0 +1,19 @@ +// provide custom privacy error for sealed traits +pub mod a { + pub trait Sealed: self::b::Hidden { + fn foo() {} + } + + struct X; + impl Sealed for X {} + impl self::b::Hidden for X {} + + mod b { + pub trait Hidden {} + } +} + +struct S; +impl a::Sealed for S {} //~ ERROR the trait bound `S: Hidden` is not satisfied + +fn main() {} diff --git a/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr b/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr new file mode 100644 index 00000000000..d1052ce3508 --- /dev/null +++ b/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr @@ -0,0 +1,16 @@ +error[E0277]: the trait bound `S: Hidden` is not satisfied + --> $DIR/sealed-trait-local.rs:17:20 + | +LL | impl a::Sealed for S {} + | ^ the trait `Hidden` is not implemented for `S` + | +note: required by a bound in `Sealed` + --> $DIR/sealed-trait-local.rs:3:23 + | +LL | pub trait Sealed: self::b::Hidden { + | ^^^^^^^^^^^^^^^ required by this bound in `Sealed` + = note: `Sealed` is a "sealed trait", because to implement it you also need to implelement `a::b::Hidden`, which is not accessible; this is usually done to force you to use one of the provided types that already implement it + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/proc-macro/derive-helper-shadowing.stderr b/tests/ui/proc-macro/derive-helper-shadowing.stderr index 7e7870b2951..566c4130846 100644 --- a/tests/ui/proc-macro/derive-helper-shadowing.stderr +++ b/tests/ui/proc-macro/derive-helper-shadowing.stderr @@ -17,7 +17,7 @@ LL | #[derive(GenHelperUse)] | ^^^^^^^^^^^^ | = note: this error originates in the derive macro `GenHelperUse` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing this attribute macro +help: consider importing this attribute macro through its public re-export | LL + use empty_helper; | @@ -32,7 +32,7 @@ LL | gen_helper_use!(); | ----------------- in this macro invocation | = note: this error originates in the macro `gen_helper_use` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing this attribute macro +help: consider importing this attribute macro through its public re-export | LL + use crate::empty_helper; | diff --git a/tests/ui/reachable/unreachable-variant.stderr b/tests/ui/reachable/unreachable-variant.stderr index 6c27a2756f7..ca1d2be65ce 100644 --- a/tests/ui/reachable/unreachable-variant.stderr +++ b/tests/ui/reachable/unreachable-variant.stderr @@ -2,7 +2,7 @@ error[E0603]: module `super_sekrit` is private --> $DIR/unreachable-variant.rs:6:21 | LL | let _x = other::super_sekrit::sooper_sekrit::baz; - | ^^^^^^^^^^^^ private module + | ^^^^^^^^^^^^ private module --- unit variant `baz` is not publicly re-exported | note: the module `super_sekrit` is defined here --> $DIR/auxiliary/unreachable_variant.rs:1:1 diff --git a/tests/ui/resolve/auxiliary/issue-112831-aux.rs b/tests/ui/resolve/auxiliary/issue-112831-aux.rs new file mode 100644 index 00000000000..df436fb9929 --- /dev/null +++ b/tests/ui/resolve/auxiliary/issue-112831-aux.rs @@ -0,0 +1,13 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +struct Zeroable; + +#[proc_macro_derive(Zeroable)] +pub fn derive_zeroable(_: proc_macro::TokenStream) -> proc_macro::TokenStream { + proc_macro::TokenStream::default() +} diff --git a/tests/ui/resolve/issue-112831.rs b/tests/ui/resolve/issue-112831.rs new file mode 100644 index 00000000000..ffd83ea8bc1 --- /dev/null +++ b/tests/ui/resolve/issue-112831.rs @@ -0,0 +1,20 @@ +// check-pass +// aux-build:issue-112831-aux.rs + +mod zeroable { + pub trait Zeroable {} +} + +use zeroable::*; + +mod pod { + use super::*; + pub trait Pod: Zeroable {} +} + +use pod::*; + +extern crate issue_112831_aux; +use issue_112831_aux::Zeroable; + +fn main() {} diff --git a/tests/ui/resolve/privacy-enum-ctor.stderr b/tests/ui/resolve/privacy-enum-ctor.stderr index 0bb09090569..b10eded015f 100644 --- a/tests/ui/resolve/privacy-enum-ctor.stderr +++ b/tests/ui/resolve/privacy-enum-ctor.stderr @@ -228,7 +228,9 @@ error[E0603]: enum `Z` is private --> $DIR/privacy-enum-ctor.rs:61:22 | LL | let _: Z = m::n::Z::Fn; - | ^ private enum + | ^ -- tuple variant `Fn` is not publicly re-exported + | | + | private enum | note: the enum `Z` is defined here --> $DIR/privacy-enum-ctor.rs:11:9 @@ -252,7 +254,9 @@ error[E0603]: enum `Z` is private --> $DIR/privacy-enum-ctor.rs:68:22 | LL | let _: Z = m::n::Z::Unit {}; - | ^ private enum + | ^ ---- variant `Unit` is not publicly re-exported + | | + | private enum | note: the enum `Z` is defined here --> $DIR/privacy-enum-ctor.rs:11:9 diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/attr-misuse.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/attr-misuse.stderr index b18f33218c2..998958cedf7 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/attr-misuse.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/attr-misuse.stderr @@ -3,12 +3,16 @@ error: attribute should be applied to a trait | LL | #[const_trait] | ^^^^^^^^^^^^^^ +LL | fn main() {} + | ------------ not a trait error: attribute should be applied to a trait --> $DIR/attr-misuse.rs:5:5 | LL | #[const_trait] | ^^^^^^^^^^^^^^ +LL | fn foo(self); + | ------------- not a trait error: aborting due to 2 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr new file mode 100644 index 00000000000..bd0dd126c5e --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr @@ -0,0 +1,26 @@ +error[E0277]: can't compare `str` with `str` in const contexts + --> $DIR/match-non-const-eq.rs:6:9 + | +LL | "a" => (), + | ^^^ no implementation for `str == str` + | + = help: the trait `~const PartialEq` is not implemented for `str` +note: the trait `PartialEq` is implemented for `str`, but that implementation is not `const` + --> $DIR/match-non-const-eq.rs:6:9 + | +LL | "a" => (), + | ^^^ + +error[E0015]: cannot match on `str` in constant functions + --> $DIR/match-non-const-eq.rs:6:9 + | +LL | "a" => (), + | ^^^ + | + = note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.rs new file mode 100644 index 00000000000..0d04101a383 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.rs @@ -0,0 +1,12 @@ +// revisions: stock gated +#![cfg_attr(gated, feature(const_trait_impl))] + +const fn foo(input: &'static str) { + match input { + "a" => (), //[gated]~ ERROR can't compare `str` with `str` in const contexts + //~^ ERROR cannot match on `str` in constant functions + _ => (), + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.stock.stderr new file mode 100644 index 00000000000..dcb9b49ea04 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.stock.stderr @@ -0,0 +1,13 @@ +error[E0015]: cannot match on `str` in constant functions + --> $DIR/match-non-const-eq.rs:6:9 + | +LL | "a" => (), + | ^^^ + | + = note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/stability-attribute/stability-in-private-module.stderr b/tests/ui/stability-attribute/stability-in-private-module.stderr index 2f02a24960e..cc8758714fc 100644 --- a/tests/ui/stability-attribute/stability-in-private-module.stderr +++ b/tests/ui/stability-attribute/stability-in-private-module.stderr @@ -2,7 +2,9 @@ error[E0603]: module `thread_info` is private --> $DIR/stability-in-private-module.rs:2:26 | LL | let _ = std::thread::thread_info::current_thread(); - | ^^^^^^^^^^^ private module + | ^^^^^^^^^^^ -------------- function `current_thread` is not publicly re-exported + | | + | private module | note: the module `thread_info` is defined here --> $SRC_DIR/std/src/thread/mod.rs:LL:COL diff --git a/tests/ui/stdlib-unit-tests/not-sync.rs b/tests/ui/stdlib-unit-tests/not-sync.rs index f4648994fa9..e9395ae9e81 100644 --- a/tests/ui/stdlib-unit-tests/not-sync.rs +++ b/tests/ui/stdlib-unit-tests/not-sync.rs @@ -17,6 +17,4 @@ fn main() { test::<Receiver<i32>>(); //~^ ERROR `std::sync::mpsc::Receiver<i32>` cannot be shared between threads safely [E0277] - test::<Sender<i32>>(); - //~^ ERROR `Sender<i32>` cannot be shared between threads safely [E0277] } diff --git a/tests/ui/stdlib-unit-tests/not-sync.stderr b/tests/ui/stdlib-unit-tests/not-sync.stderr index 4e34e10e377..b9a266e4eb9 100644 --- a/tests/ui/stdlib-unit-tests/not-sync.stderr +++ b/tests/ui/stdlib-unit-tests/not-sync.stderr @@ -65,19 +65,6 @@ note: required by a bound in `test` LL | fn test<T: Sync>() {} | ^^^^ required by this bound in `test` -error[E0277]: `Sender<i32>` cannot be shared between threads safely - --> $DIR/not-sync.rs:20:12 - | -LL | test::<Sender<i32>>(); - | ^^^^^^^^^^^ `Sender<i32>` cannot be shared between threads safely - | - = help: the trait `Sync` is not implemented for `Sender<i32>` -note: required by a bound in `test` - --> $DIR/not-sync.rs:5:12 - | -LL | fn test<T: Sync>() {} - | ^^^^ required by this bound in `test` - -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/structs/struct-variant-privacy-xc.stderr b/tests/ui/structs/struct-variant-privacy-xc.stderr index 1c1caaef8b7..7a1c84badef 100644 --- a/tests/ui/structs/struct-variant-privacy-xc.stderr +++ b/tests/ui/structs/struct-variant-privacy-xc.stderr @@ -14,7 +14,9 @@ error[E0603]: enum `Bar` is private --> $DIR/struct-variant-privacy-xc.rs:7:33 | LL | struct_variant_privacy::Bar::Baz { a: _a } => {} - | ^^^ private enum + | ^^^ --- variant `Baz` is not publicly re-exported + | | + | private enum | note: the enum `Bar` is defined here --> $DIR/auxiliary/struct_variant_privacy.rs:1:1 diff --git a/tests/ui/structs/struct-variant-privacy.stderr b/tests/ui/structs/struct-variant-privacy.stderr index eafd26c716f..eabd66907f6 100644 --- a/tests/ui/structs/struct-variant-privacy.stderr +++ b/tests/ui/structs/struct-variant-privacy.stderr @@ -14,7 +14,9 @@ error[E0603]: enum `Bar` is private --> $DIR/struct-variant-privacy.rs:10:14 | LL | foo::Bar::Baz { a: _a } => {} - | ^^^ private enum + | ^^^ --- variant `Baz` is not publicly re-exported + | | + | private enum | note: the enum `Bar` is defined here --> $DIR/struct-variant-privacy.rs:2:5 diff --git a/tests/ui/test-attrs/test-function-signature.rs b/tests/ui/test-attrs/test-function-signature.rs new file mode 100644 index 00000000000..9e86e9209e3 --- /dev/null +++ b/tests/ui/test-attrs/test-function-signature.rs @@ -0,0 +1,31 @@ +// compile-flags: --test + +#[test] +fn foo() -> Result<(), ()> { + Ok(()) +} + +#[test] +fn bar() -> i32 { //~ ERROR the trait bound `i32: Termination` is not satisfied + 0 +} + +#[test] +fn baz(val: i32) {} //~ ERROR functions used as tests can not have any arguments + +#[test] +fn lifetime_generic<'a>() -> Result<(), &'a str> { + Err("coerce me to any lifetime") +} + +#[test] +fn type_generic<T>() {} //~ ERROR functions used as tests can not have any non-lifetime generic parameters + +#[test] +fn const_generic<const N: usize>() {} //~ ERROR functions used as tests can not have any non-lifetime generic parameters + +// Regression test for <https://github.com/rust-lang/rust/issues/112360>. This used to ICE. +fn nested() { + #[test] + fn foo(arg: ()) {} //~ ERROR functions used as tests can not have any arguments +} diff --git a/tests/ui/test-attrs/test-function-signature.stderr b/tests/ui/test-attrs/test-function-signature.stderr new file mode 100644 index 00000000000..abdb30dc931 --- /dev/null +++ b/tests/ui/test-attrs/test-function-signature.stderr @@ -0,0 +1,39 @@ +error: functions used as tests can not have any arguments + --> $DIR/test-function-signature.rs:14:1 + | +LL | fn baz(val: i32) {} + | ^^^^^^^^^^^^^^^^^^^ + +error: functions used as tests can not have any non-lifetime generic parameters + --> $DIR/test-function-signature.rs:22:1 + | +LL | fn type_generic<T>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions used as tests can not have any non-lifetime generic parameters + --> $DIR/test-function-signature.rs:25:1 + | +LL | fn const_generic<const N: usize>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions used as tests can not have any arguments + --> $DIR/test-function-signature.rs:30:5 + | +LL | fn foo(arg: ()) {} + | ^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `i32: Termination` is not satisfied + --> $DIR/test-function-signature.rs:9:13 + | +LL | #[test] + | ------- in this procedural macro expansion +LL | fn bar() -> i32 { + | ^^^ the trait `Termination` is not implemented for `i32` + | +note: required by a bound in `assert_test_result` + --> $SRC_DIR/test/src/lib.rs:LL:COL + = note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/test-attrs/test-panic-abort-disabled.rs b/tests/ui/test-attrs/test-panic-abort-disabled.rs index 874dbdb42c3..fa67a784de4 100644 --- a/tests/ui/test-attrs/test-panic-abort-disabled.rs +++ b/tests/ui/test-attrs/test-panic-abort-disabled.rs @@ -3,6 +3,7 @@ // compile-flags: --test -Cpanic=abort -Zpanic-abort-tests=no // run-flags: --test-threads=1 +// needs-unwind // ignore-wasm no panic or subprocess support // ignore-emscripten no panic or subprocess support diff --git a/tests/ui/test-attrs/test-type.rs b/tests/ui/test-attrs/test-type.rs index 8416270fd81..d6d44a6b446 100644 --- a/tests/ui/test-attrs/test-type.rs +++ b/tests/ui/test-attrs/test-type.rs @@ -1,9 +1,8 @@ -// compile-flags: --test +// compile-flags: --test -Zpanic-abort-tests // run-flags: --test-threads=1 // check-run-results // normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" // ignore-emscripten no threads support -// needs-unwind // run-pass #[test] diff --git a/tests/ui/traits/cache-reached-depth-ice.rs b/tests/ui/traits/cache-reached-depth-ice.rs index c36ac08579b..8c2391113d7 100644 --- a/tests/ui/traits/cache-reached-depth-ice.rs +++ b/tests/ui/traits/cache-reached-depth-ice.rs @@ -41,5 +41,5 @@ fn test<X: ?Sized + Send>() {} fn main() { test::<A>(); - //~^ ERROR evaluate(Binder(TraitPredicate(<A as std::marker::Send>, polarity:Positive), [])) = Ok(EvaluatedToOk) + //~^ ERROR evaluate(Binder { value: TraitPredicate(<A as std::marker::Send>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) } diff --git a/tests/ui/traits/cache-reached-depth-ice.stderr b/tests/ui/traits/cache-reached-depth-ice.stderr index 082aa0f5cd9..7cd75819277 100644 --- a/tests/ui/traits/cache-reached-depth-ice.stderr +++ b/tests/ui/traits/cache-reached-depth-ice.stderr @@ -1,4 +1,4 @@ -error: evaluate(Binder(TraitPredicate(<A as std::marker::Send>, polarity:Positive), [])) = Ok(EvaluatedToOk) +error: evaluate(Binder { value: TraitPredicate(<A as std::marker::Send>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) --> $DIR/cache-reached-depth-ice.rs:43:5 | LL | fn test<X: ?Sized + Send>() {} diff --git a/tests/ui/traits/deny-builtin-object-impl.current.stderr b/tests/ui/traits/deny-builtin-object-impl.current.stderr new file mode 100644 index 00000000000..5c1987426f7 --- /dev/null +++ b/tests/ui/traits/deny-builtin-object-impl.current.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `dyn NotObject: NotObject` is not satisfied + --> $DIR/deny-builtin-object-impl.rs:18:23 + | +LL | test_not_object::<dyn NotObject>(); + | ^^^^^^^^^^^^^ the trait `NotObject` is not implemented for `dyn NotObject` + | +note: required by a bound in `test_not_object` + --> $DIR/deny-builtin-object-impl.rs:14:23 + | +LL | fn test_not_object<T: NotObject + ?Sized>() {} + | ^^^^^^^^^ required by this bound in `test_not_object` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/deny-builtin-object-impl.next.stderr b/tests/ui/traits/deny-builtin-object-impl.next.stderr new file mode 100644 index 00000000000..5c1987426f7 --- /dev/null +++ b/tests/ui/traits/deny-builtin-object-impl.next.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `dyn NotObject: NotObject` is not satisfied + --> $DIR/deny-builtin-object-impl.rs:18:23 + | +LL | test_not_object::<dyn NotObject>(); + | ^^^^^^^^^^^^^ the trait `NotObject` is not implemented for `dyn NotObject` + | +note: required by a bound in `test_not_object` + --> $DIR/deny-builtin-object-impl.rs:14:23 + | +LL | fn test_not_object<T: NotObject + ?Sized>() {} + | ^^^^^^^^^ required by this bound in `test_not_object` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/deny-builtin-object-impl.rs b/tests/ui/traits/deny-builtin-object-impl.rs new file mode 100644 index 00000000000..dce03a43b68 --- /dev/null +++ b/tests/ui/traits/deny-builtin-object-impl.rs @@ -0,0 +1,20 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + +#![feature(rustc_attrs)] + +#[rustc_deny_explicit_impl(implement_via_object = true)] +trait YesObject {} + +#[rustc_deny_explicit_impl(implement_via_object = false)] +trait NotObject {} + +fn test_yes_object<T: YesObject + ?Sized>() {} + +fn test_not_object<T: NotObject + ?Sized>() {} + +fn main() { + test_yes_object::<dyn YesObject>(); + test_not_object::<dyn NotObject>(); + //~^ ERROR the trait bound `dyn NotObject: NotObject` is not satisfied +} diff --git a/tests/ui/traits/issue-83538-tainted-cache-after-cycle.rs b/tests/ui/traits/issue-83538-tainted-cache-after-cycle.rs index 3cd68ff6f06..5136aef4f7a 100644 --- a/tests/ui/traits/issue-83538-tainted-cache-after-cycle.rs +++ b/tests/ui/traits/issue-83538-tainted-cache-after-cycle.rs @@ -57,10 +57,10 @@ fn main() { // Key is that Vec<First> is "ok" and Third<'_, Ty> is "ok modulo regions": forward(); - //~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk) - //~| ERROR evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) + //~^ ERROR evaluate(Binder { value: TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) + //~| ERROR evaluate(Binder { value: TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) reverse(); - //~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk) - //~| ERROR evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) + //~^ ERROR evaluate(Binder { value: TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) + //~| ERROR evaluate(Binder { value: TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) } diff --git a/tests/ui/traits/issue-83538-tainted-cache-after-cycle.stderr b/tests/ui/traits/issue-83538-tainted-cache-after-cycle.stderr index 7c4041144a4..96baec76a17 100644 --- a/tests/ui/traits/issue-83538-tainted-cache-after-cycle.stderr +++ b/tests/ui/traits/issue-83538-tainted-cache-after-cycle.stderr @@ -1,4 +1,4 @@ -error: evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk) +error: evaluate(Binder { value: TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) --> $DIR/issue-83538-tainted-cache-after-cycle.rs:59:5 | LL | Vec<First>: Unpin, @@ -7,7 +7,7 @@ LL | Vec<First>: Unpin, LL | forward(); | ^^^^^^^ -error: evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) +error: evaluate(Binder { value: TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) --> $DIR/issue-83538-tainted-cache-after-cycle.rs:59:5 | LL | Third<'a, Ty>: Unpin, @@ -16,7 +16,7 @@ LL | Third<'a, Ty>: Unpin, LL | forward(); | ^^^^^^^ -error: evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) +error: evaluate(Binder { value: TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) --> $DIR/issue-83538-tainted-cache-after-cycle.rs:63:5 | LL | Third<'a, Ty>: Unpin, @@ -25,7 +25,7 @@ LL | Third<'a, Ty>: Unpin, LL | reverse(); | ^^^^^^^ -error: evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk) +error: evaluate(Binder { value: TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) --> $DIR/issue-83538-tainted-cache-after-cycle.rs:63:5 | LL | Vec<First>: Unpin, diff --git a/tests/ui/traits/issue-85360-eval-obligation-ice.rs b/tests/ui/traits/issue-85360-eval-obligation-ice.rs index 19131684a48..ac8bda9c010 100644 --- a/tests/ui/traits/issue-85360-eval-obligation-ice.rs +++ b/tests/ui/traits/issue-85360-eval-obligation-ice.rs @@ -7,12 +7,12 @@ use core::marker::PhantomData; fn main() { test::<MaskedStorage<GenericComp<Pos>>>(make()); - //~^ ERROR evaluate(Binder(TraitPredicate(<MaskedStorage<GenericComp<Pos>> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOk) - //~| ERROR evaluate(Binder(TraitPredicate(<MaskedStorage<GenericComp<Pos>> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOk) + //~^ ERROR evaluate(Binder { value: TraitPredicate(<MaskedStorage<GenericComp<Pos>> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) + //~| ERROR evaluate(Binder { value: TraitPredicate(<MaskedStorage<GenericComp<Pos>> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) test::<MaskedStorage<GenericComp2<Pos>>>(make()); - //~^ ERROR evaluate(Binder(TraitPredicate(<MaskedStorage<GenericComp2<Pos>> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) - //~| ERROR evaluate(Binder(TraitPredicate(<MaskedStorage<GenericComp2<Pos>> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) + //~^ ERROR evaluate(Binder { value: TraitPredicate(<MaskedStorage<GenericComp2<Pos>> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) + //~| ERROR evaluate(Binder { value: TraitPredicate(<MaskedStorage<GenericComp2<Pos>> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) } #[rustc_evaluate_where_clauses] diff --git a/tests/ui/traits/issue-85360-eval-obligation-ice.stderr b/tests/ui/traits/issue-85360-eval-obligation-ice.stderr index ebf977dd680..9590ea12c05 100644 --- a/tests/ui/traits/issue-85360-eval-obligation-ice.stderr +++ b/tests/ui/traits/issue-85360-eval-obligation-ice.stderr @@ -1,4 +1,4 @@ -error: evaluate(Binder(TraitPredicate(<MaskedStorage<GenericComp<Pos>> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOk) +error: evaluate(Binder { value: TraitPredicate(<MaskedStorage<GenericComp<Pos>> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) --> $DIR/issue-85360-eval-obligation-ice.rs:9:5 | LL | test::<MaskedStorage<GenericComp<Pos>>>(make()); @@ -7,7 +7,7 @@ LL | test::<MaskedStorage<GenericComp<Pos>>>(make()); LL | fn test<T: Sized>(_: T) {} | - predicate -error: evaluate(Binder(TraitPredicate(<MaskedStorage<GenericComp<Pos>> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOk) +error: evaluate(Binder { value: TraitPredicate(<MaskedStorage<GenericComp<Pos>> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) --> $DIR/issue-85360-eval-obligation-ice.rs:9:5 | LL | test::<MaskedStorage<GenericComp<Pos>>>(make()); @@ -16,7 +16,7 @@ LL | test::<MaskedStorage<GenericComp<Pos>>>(make()); LL | fn test<T: Sized>(_: T) {} | ----- predicate -error: evaluate(Binder(TraitPredicate(<MaskedStorage<GenericComp2<Pos>> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) +error: evaluate(Binder { value: TraitPredicate(<MaskedStorage<GenericComp2<Pos>> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) --> $DIR/issue-85360-eval-obligation-ice.rs:13:5 | LL | test::<MaskedStorage<GenericComp2<Pos>>>(make()); @@ -25,7 +25,7 @@ LL | test::<MaskedStorage<GenericComp2<Pos>>>(make()); LL | fn test<T: Sized>(_: T) {} | - predicate -error: evaluate(Binder(TraitPredicate(<MaskedStorage<GenericComp2<Pos>> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) +error: evaluate(Binder { value: TraitPredicate(<MaskedStorage<GenericComp2<Pos>> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) --> $DIR/issue-85360-eval-obligation-ice.rs:13:5 | LL | test::<MaskedStorage<GenericComp2<Pos>>>(make()); diff --git a/tests/ui/traits/new-solver/alias-bound-unsound.rs b/tests/ui/traits/new-solver/alias-bound-unsound.rs index 00294c708f1..6b6a77e2c7e 100644 --- a/tests/ui/traits/new-solver/alias-bound-unsound.rs +++ b/tests/ui/traits/new-solver/alias-bound-unsound.rs @@ -23,5 +23,7 @@ fn main() { drop(<() as Foo>::copy_me(&x)); //~^ ERROR `<() as Foo>::Item: Copy` is not satisfied //~| ERROR `<() as Foo>::Item` is not well-formed + //~| ERROR `<() as Foo>::Item` is not well-formed + //~| ERROR `<() as Foo>::Item` is not well-formed println!("{x}"); } diff --git a/tests/ui/traits/new-solver/alias-bound-unsound.stderr b/tests/ui/traits/new-solver/alias-bound-unsound.stderr index 9a43d2a6639..89abc608213 100644 --- a/tests/ui/traits/new-solver/alias-bound-unsound.stderr +++ b/tests/ui/traits/new-solver/alias-bound-unsound.stderr @@ -19,6 +19,18 @@ error: the type `<() as Foo>::Item` is not well-formed LL | drop(<() as Foo>::copy_me(&x)); | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: the type `<() as Foo>::Item` is not well-formed + --> $DIR/alias-bound-unsound.rs:23:5 + | +LL | drop(<() as Foo>::copy_me(&x)); + | ^^^^ + +error: the type `<() as Foo>::Item` is not well-formed + --> $DIR/alias-bound-unsound.rs:23:10 + | +LL | drop(<() as Foo>::copy_me(&x)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.rs b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.rs new file mode 100644 index 00000000000..96a7424f0dc --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.rs @@ -0,0 +1,12 @@ +#![feature(non_lifetime_binders)] +//~^ WARN the feature `non_lifetime_binders` is incomplete + +fn auto_trait() +where + for<T> T: PartialEq + PartialOrd, +{} + +fn main() { + auto_trait(); + //~^ ERROR can't compare `T` with `T` +} diff --git a/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.stderr b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.stderr new file mode 100644 index 00000000000..da09343fb27 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.stderr @@ -0,0 +1,28 @@ +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/foreach-partial-eq.rs:1:12 + | +LL | #![feature(non_lifetime_binders)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: can't compare `T` with `T` + --> $DIR/foreach-partial-eq.rs:10:5 + | +LL | auto_trait(); + | ^^^^^^^^^^ no implementation for `T < T` and `T > T` + | + = help: the trait `PartialOrd` is not implemented for `T` +note: required by a bound in `auto_trait` + --> $DIR/foreach-partial-eq.rs:6:27 + | +LL | fn auto_trait() + | ---------- required by a bound in this function +LL | where +LL | for<T> T: PartialEq + PartialOrd, + | ^^^^^^^^^^ required by this bound in `auto_trait` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/project-modulo-regions.rs b/tests/ui/traits/project-modulo-regions.rs index f0c0dd3ed95..e88f21ecfe8 100644 --- a/tests/ui/traits/project-modulo-regions.rs +++ b/tests/ui/traits/project-modulo-regions.rs @@ -48,8 +48,8 @@ fn test(val: MyStruct) where Helper: HelperTrait { fn foo(val: MyStruct) { test(val); - //[with_clause]~^ ERROR evaluate(Binder(TraitPredicate(<Helper as HelperTrait>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) - //[without_clause]~^^ ERROR evaluate(Binder(TraitPredicate(<Helper as HelperTrait>, polarity:Positive), [])) = Ok(EvaluatedToOk) + //[with_clause]~^ ERROR evaluate(Binder { value: TraitPredicate(<Helper as HelperTrait>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) + //[without_clause]~^^ ERROR evaluate(Binder { value: TraitPredicate(<Helper as HelperTrait>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) } fn main() {} diff --git a/tests/ui/traits/project-modulo-regions.with_clause.stderr b/tests/ui/traits/project-modulo-regions.with_clause.stderr index 2434c32c818..dcc98e855d1 100644 --- a/tests/ui/traits/project-modulo-regions.with_clause.stderr +++ b/tests/ui/traits/project-modulo-regions.with_clause.stderr @@ -1,4 +1,4 @@ -error: evaluate(Binder(TraitPredicate(<Helper as HelperTrait>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) +error: evaluate(Binder { value: TraitPredicate(<Helper as HelperTrait>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) --> $DIR/project-modulo-regions.rs:50:5 | LL | fn test(val: MyStruct) where Helper: HelperTrait { diff --git a/tests/ui/traits/project-modulo-regions.without_clause.stderr b/tests/ui/traits/project-modulo-regions.without_clause.stderr index 9d35690d5f0..e9959567e06 100644 --- a/tests/ui/traits/project-modulo-regions.without_clause.stderr +++ b/tests/ui/traits/project-modulo-regions.without_clause.stderr @@ -1,4 +1,4 @@ -error: evaluate(Binder(TraitPredicate(<Helper as HelperTrait>, polarity:Positive), [])) = Ok(EvaluatedToOk) +error: evaluate(Binder { value: TraitPredicate(<Helper as HelperTrait>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) --> $DIR/project-modulo-regions.rs:50:5 | LL | fn test(val: MyStruct) where Helper: HelperTrait { diff --git a/tests/ui/type-alias-impl-trait/debug-ty-with-weak.rs b/tests/ui/type-alias-impl-trait/debug-ty-with-weak.rs new file mode 100644 index 00000000000..44158349fdd --- /dev/null +++ b/tests/ui/type-alias-impl-trait/debug-ty-with-weak.rs @@ -0,0 +1,12 @@ +// compile-flags: --crate-type=lib -Cdebuginfo=2 +// build-pass + +#![feature(type_alias_impl_trait)] + +type Debuggable = impl core::fmt::Debug; + +static mut TEST: Option<Debuggable> = None; + +fn foo() -> Debuggable { + 0u32 +} diff --git a/tests/ui/type-alias-impl-trait/hidden_behind_projection_behind_struct_field.rs b/tests/ui/type-alias-impl-trait/hidden_behind_projection_behind_struct_field.rs new file mode 100644 index 00000000000..eb19b49c7e2 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/hidden_behind_projection_behind_struct_field.rs @@ -0,0 +1,28 @@ +//! This test shows that a field type that is a projection that resolves to an opaque, +//! is not a defining use. While we could substitute the struct generics, that would +//! mean we would have to walk all substitutions of an `Foo`, which can quickly +//! degenerate into looking at an exponential number of types depending on the complexity +//! of a program. + +#![feature(impl_trait_in_assoc_type)] + +struct Bar; + +trait Trait: Sized { + type Assoc; + fn foo() -> Foo<Self>; +} + +impl Trait for Bar { + type Assoc = impl std::fmt::Debug; + fn foo() -> Foo<Bar> { + Foo { field: () } + //~^ ERROR: mismatched types + } +} + +struct Foo<T: Trait> { + field: <T as Trait>::Assoc, +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/hidden_behind_projection_behind_struct_field.stderr b/tests/ui/type-alias-impl-trait/hidden_behind_projection_behind_struct_field.stderr new file mode 100644 index 00000000000..648efd1cbfe --- /dev/null +++ b/tests/ui/type-alias-impl-trait/hidden_behind_projection_behind_struct_field.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/hidden_behind_projection_behind_struct_field.rs:19:22 + | +LL | type Assoc = impl std::fmt::Debug; + | -------------------- the expected opaque type +LL | fn foo() -> Foo<Bar> { +LL | Foo { field: () } + | ^^ expected opaque type, found `()` + | + = note: expected opaque type `<Bar as Trait>::Assoc` + found unit type `()` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/hidden_behind_projection_behind_struct_field.rs:18:8 + | +LL | fn foo() -> Foo<Bar> { + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-alias-impl-trait/hidden_behind_struct_field.rs b/tests/ui/type-alias-impl-trait/hidden_behind_struct_field.rs new file mode 100644 index 00000000000..58778702de6 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/hidden_behind_struct_field.rs @@ -0,0 +1,30 @@ +//! This test shows that the appearance of an opaque type +//! in the substs of a struct are enough to make it count +//! for making the function a defining use. It doesn't matter +//! if the opaque type is actually used in the field. + +#![feature(impl_trait_in_assoc_type)] +// check-pass + +use std::marker::PhantomData; + +struct Bar; + +trait Trait: Sized { + type Assoc; + fn foo() -> Foo<Self::Assoc>; +} + +impl Trait for Bar { + type Assoc = impl std::fmt::Debug; + fn foo() -> Foo<Self::Assoc> { + let foo: Foo<()> = Foo { field: PhantomData }; + foo + } +} + +struct Foo<T> { + field: PhantomData<T>, +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.rs b/tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.rs new file mode 100644 index 00000000000..e440dce5e51 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.rs @@ -0,0 +1,26 @@ +//! This test shows that we can even follow projections +//! into associated types of the same impl if they are +//! indirectly mentioned in a struct field. + +#![feature(impl_trait_in_assoc_type)] +// check-pass + +struct Bar; + +trait Trait: Sized { + type Assoc; + fn foo() -> Foo; +} + +impl Trait for Bar { + type Assoc = impl std::fmt::Debug; + fn foo() -> Foo { + Foo { field: () } + } +} + +struct Foo { + field: <Bar as Trait>::Assoc, +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/higher_kinded_params3.rs b/tests/ui/type-alias-impl-trait/higher_kinded_params3.rs new file mode 100644 index 00000000000..839a611cb71 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/higher_kinded_params3.rs @@ -0,0 +1,35 @@ +//! This test checks that we can't actually have an opaque type behind +//! a binder that references variables from that binder. + +// edition: 2021 + +#![feature(type_alias_impl_trait)] + +trait B { + type C; +} + +struct A; + +impl<'a> B for &'a A { + type C = Tait<'a>; +} + +type Tait<'a> = impl std::fmt::Debug + 'a; + +struct Terminator; + +type Successors<'a> = impl std::fmt::Debug + 'a; + +impl Terminator { + fn successors(&self, mut f: for<'x> fn(&'x ()) -> <&'x A as B>::C) -> Successors<'_> { + f = g; + //~^ ERROR: mismatched types + } +} + +fn g(x: &()) -> &() { + x +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/higher_kinded_params3.stderr b/tests/ui/type-alias-impl-trait/higher_kinded_params3.stderr new file mode 100644 index 00000000000..aaba9ad5ca7 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/higher_kinded_params3.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/higher_kinded_params3.rs:26:9 + | +LL | type Tait<'a> = impl std::fmt::Debug + 'a; + | ------------------------- the expected opaque type +... +LL | f = g; + | ^^^^^ one type is more general than the other + | + = note: expected fn pointer `for<'x> fn(&'x ()) -> Tait<'x>` + found fn pointer `for<'a> fn(&'a ()) -> &'a ()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.rs b/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.rs new file mode 100644 index 00000000000..a3f65146f75 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.rs @@ -0,0 +1,28 @@ +#![feature(impl_trait_in_assoc_type)] + +// We weren't checking that the trait and impl generics line up in the +// normalization-shortcut code in `OpaqueTypeCollector`. + +use std::ops::Deref; + +trait Foo { + type Bar<'a>; + + type Baz<'a>; + + fn test<'a>() -> Self::Bar<'a>; +} + +impl Foo for () { + type Bar<'a> = impl Deref<Target = Self::Baz<'a>>; + + type Baz<T> = impl Sized; + //~^ ERROR type `Baz` has 1 type parameter but its trait declaration has 0 type parameters + //~| ERROR unconstrained opaque type + + fn test<'a>() -> Self::Bar<'a> { + &() + } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.stderr b/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.stderr new file mode 100644 index 00000000000..13f5d8b8ea6 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.stderr @@ -0,0 +1,20 @@ +error[E0049]: type `Baz` has 1 type parameter but its trait declaration has 0 type parameters + --> $DIR/impl-trait-in-type-alias-with-bad-substs.rs:19:14 + | +LL | type Baz<'a>; + | -- expected 0 type parameters +... +LL | type Baz<T> = impl Sized; + | ^ found 1 type parameter + +error: unconstrained opaque type + --> $DIR/impl-trait-in-type-alias-with-bad-substs.rs:19:19 + | +LL | type Baz<T> = impl Sized; + | ^^^^^^^^^^ + | + = note: `Baz` must be used in combination with a concrete type within the same impl + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0049`. diff --git a/tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.stderr b/tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.stderr index 2beed73cb85..6ec5d13f812 100644 --- a/tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.stderr +++ b/tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.stderr @@ -12,10 +12,10 @@ LL | let x: Self::Foo = (); = note: expected opaque type `<() as Foo>::Foo` found unit type `()` note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/invalid_impl_trait_in_assoc_ty.rs:10:5 + --> $DIR/invalid_impl_trait_in_assoc_ty.rs:10:8 | LL | fn bar() { - | ^^^^^^^^ + | ^^^ error: aborting due to previous error diff --git a/tests/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs b/tests/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs index b97e444c6d0..386b77d4d16 100644 --- a/tests/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs +++ b/tests/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs @@ -1,6 +1,8 @@ // Regression test for issue #76202 // Tests that we don't ICE when we have a trait impl on a TAIT. +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next // check-pass #![feature(type_alias_impl_trait)] diff --git a/tests/ui/type-alias-impl-trait/multi-error.rs b/tests/ui/type-alias-impl-trait/multi-error.rs new file mode 100644 index 00000000000..b5ff06572d0 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/multi-error.rs @@ -0,0 +1,23 @@ +//! This test checks that we don't follow up +//! with type mismatch errors of opaque types +//! with their hidden types if we failed the +//! defining scope check at the signature level. + +#![feature(impl_trait_in_assoc_type)] + +trait Foo { + type Bar<T>; + type Baz; + fn foo() -> (Self::Bar<u32>, Self::Baz); +} + +impl Foo for () { + type Bar<T> = impl Sized; + type Baz = impl Sized; + fn foo() -> (Self::Bar<u32>, Self::Baz) { + //~^ ERROR non-defining opaque type use + ((), ()) + } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/multi-error.stderr b/tests/ui/type-alias-impl-trait/multi-error.stderr new file mode 100644 index 00000000000..b2de2effea6 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/multi-error.stderr @@ -0,0 +1,15 @@ +error[E0792]: non-defining opaque type use in defining scope + --> $DIR/multi-error.rs:17:17 + | +LL | fn foo() -> (Self::Bar<u32>, Self::Baz) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument `u32` is not a generic parameter + | +note: for this opaque type + --> $DIR/multi-error.rs:15:19 + | +LL | type Bar<T> = impl Sized; + | ^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/non-defining-method.rs b/tests/ui/type-alias-impl-trait/non-defining-method.rs new file mode 100644 index 00000000000..2f4a7052f72 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/non-defining-method.rs @@ -0,0 +1,21 @@ +//! This test checks that we don't follow up +//! with type mismatch errors of opaque types +//! with their hidden types if we failed the +//! defining scope check at the signature level. + +#![feature(impl_trait_in_assoc_type)] + +trait Foo { + type Bar<T>; + fn foo() -> Self::Bar<u32>; + fn bar<T>() -> Self::Bar<T>; +} + +impl Foo for () { + type Bar<T> = impl Sized; + fn foo() -> Self::Bar<u32> {} + //~^ ERROR non-defining opaque type use + fn bar<T>() -> Self::Bar<T> {} +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/non-defining-method.stderr b/tests/ui/type-alias-impl-trait/non-defining-method.stderr new file mode 100644 index 00000000000..ed5590f9d71 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/non-defining-method.stderr @@ -0,0 +1,15 @@ +error[E0792]: non-defining opaque type use in defining scope + --> $DIR/non-defining-method.rs:16:17 + | +LL | fn foo() -> Self::Bar<u32> {} + | ^^^^^^^^^^^^^^ argument `u32` is not a generic parameter + | +note: for this opaque type + --> $DIR/non-defining-method.rs:15:19 + | +LL | type Bar<T> = impl Sized; + | ^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/not-matching-trait-refs-isnt-defining.rs b/tests/ui/type-alias-impl-trait/not-matching-trait-refs-isnt-defining.rs new file mode 100644 index 00000000000..131f8d999d8 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/not-matching-trait-refs-isnt-defining.rs @@ -0,0 +1,33 @@ +#![feature(impl_trait_in_assoc_type)] + +trait Foo<T> { + type Assoc; + + fn test() -> u32; +} + +struct DefinesOpaque; +impl Foo<DefinesOpaque> for () { + type Assoc = impl Sized; + + // This test's return type is `u32`, *not* the opaque that is defined above. + // Previously we were only checking that the self type of the assoc matched, + // but this doesn't account for other impls with different trait substs. + fn test() -> <() as Foo<NoOpaques>>::Assoc { + let _: <Self as Foo<DefinesOpaque>>::Assoc = ""; + //~^ ERROR mismatched types + + 1 + } +} + +struct NoOpaques; +impl Foo<NoOpaques> for () { + type Assoc = u32; + + fn test() -> u32 { + 1 + } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/not-matching-trait-refs-isnt-defining.stderr b/tests/ui/type-alias-impl-trait/not-matching-trait-refs-isnt-defining.stderr new file mode 100644 index 00000000000..a621bb519cd --- /dev/null +++ b/tests/ui/type-alias-impl-trait/not-matching-trait-refs-isnt-defining.stderr @@ -0,0 +1,22 @@ +error[E0308]: mismatched types + --> $DIR/not-matching-trait-refs-isnt-defining.rs:17:54 + | +LL | type Assoc = impl Sized; + | ---------- the expected opaque type +... +LL | let _: <Self as Foo<DefinesOpaque>>::Assoc = ""; + | ----------------------------------- ^^ expected opaque type, found `&str` + | | + | expected due to this + | + = note: expected opaque type `<() as Foo<DefinesOpaque>>::Assoc` + found reference `&'static str` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/not-matching-trait-refs-isnt-defining.rs:16:8 + | +LL | fn test() -> <() as Foo<NoOpaques>>::Assoc { + | ^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-alias-impl-trait/unnameable_type.stderr b/tests/ui/type-alias-impl-trait/unnameable_type.stderr index 24f5cc8c733..e9032433494 100644 --- a/tests/ui/type-alias-impl-trait/unnameable_type.stderr +++ b/tests/ui/type-alias-impl-trait/unnameable_type.stderr @@ -25,11 +25,6 @@ LL | fn dont_define_this(_private: Private) {} | ^^^^^^^ = note: expected signature `fn(Private)` found signature `fn(MyPrivate)` -note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/unnameable_type.rs:20:5 - | -LL | fn dont_define_this(_private: MyPrivate) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/typeck/dont-record-adjustments-when-pointing-at-arg.rs b/tests/ui/typeck/dont-record-adjustments-when-pointing-at-arg.rs new file mode 100644 index 00000000000..0c2d71707c9 --- /dev/null +++ b/tests/ui/typeck/dont-record-adjustments-when-pointing-at-arg.rs @@ -0,0 +1,29 @@ +pub trait NSWindow: Sized { + fn frame(self) -> () { + unimplemented!() + } + fn setFrame_display_(self, display: ()) {} +} +impl NSWindow for () {} + +pub struct NSRect {} + +use std::ops::Deref; +struct MainThreadSafe<T = ()>(T); +impl<T> Deref for MainThreadSafe<T> { + type Target = T; + + fn deref(&self) -> &T { + unimplemented!() + } +} + +fn main() { + || { + let ns_window = MainThreadSafe(()); + // Don't record adjustments twice for `*ns_window` + (*ns_window).frame(); + ns_window.setFrame_display_(0); + //~^ ERROR mismatched types + }; +} diff --git a/tests/ui/typeck/dont-record-adjustments-when-pointing-at-arg.stderr b/tests/ui/typeck/dont-record-adjustments-when-pointing-at-arg.stderr new file mode 100644 index 00000000000..02e87d701b6 --- /dev/null +++ b/tests/ui/typeck/dont-record-adjustments-when-pointing-at-arg.stderr @@ -0,0 +1,17 @@ +error[E0308]: mismatched types + --> $DIR/dont-record-adjustments-when-pointing-at-arg.rs:26:37 + | +LL | ns_window.setFrame_display_(0); + | ----------------- ^ expected `()`, found integer + | | + | arguments to this method are incorrect + | +note: method defined here + --> $DIR/dont-record-adjustments-when-pointing-at-arg.rs:5:8 + | +LL | fn setFrame_display_(self, display: ()) {} + | ^^^^^^^^^^^^^^^^^ ----------- + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/unsized/issue-71659.stderr b/tests/ui/unsized/issue-71659.current.stderr index b57b3015e47..6b982a73952 100644 --- a/tests/ui/unsized/issue-71659.stderr +++ b/tests/ui/unsized/issue-71659.current.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `dyn Foo: CastTo<[i32]>` is not satisfied - --> $DIR/issue-71659.rs:30:15 + --> $DIR/issue-71659.rs:33:15 | LL | let x = x.cast::<[i32]>(); | ^^^^ the trait `CastTo<[i32]>` is not implemented for `dyn Foo` | note: required by a bound in `Cast::cast` - --> $DIR/issue-71659.rs:19:15 + --> $DIR/issue-71659.rs:22:15 | LL | fn cast<T: ?Sized>(&self) -> &T | ---- required by a bound in this associated function diff --git a/tests/ui/unsized/issue-71659.next.stderr b/tests/ui/unsized/issue-71659.next.stderr new file mode 100644 index 00000000000..6b982a73952 --- /dev/null +++ b/tests/ui/unsized/issue-71659.next.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `dyn Foo: CastTo<[i32]>` is not satisfied + --> $DIR/issue-71659.rs:33:15 + | +LL | let x = x.cast::<[i32]>(); + | ^^^^ the trait `CastTo<[i32]>` is not implemented for `dyn Foo` + | +note: required by a bound in `Cast::cast` + --> $DIR/issue-71659.rs:22:15 + | +LL | fn cast<T: ?Sized>(&self) -> &T + | ---- required by a bound in this associated function +LL | where +LL | Self: CastTo<T>, + | ^^^^^^^^^ required by this bound in `Cast::cast` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/unsized/issue-71659.rs b/tests/ui/unsized/issue-71659.rs index 3524ca02bbf..db5c2e205aa 100644 --- a/tests/ui/unsized/issue-71659.rs +++ b/tests/ui/unsized/issue-71659.rs @@ -1,3 +1,6 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + #![feature(unsize)] use std::marker::Unsize; diff --git a/tests/ui/use/use-keyword.rs b/tests/ui/use/use-keyword.rs index c30c2e06c45..840cddcb907 100644 --- a/tests/ui/use/use-keyword.rs +++ b/tests/ui/use/use-keyword.rs @@ -1,4 +1,4 @@ -// Check that imports with nakes super and self don't fail during parsing +// Check that imports with naked super and self don't fail during parsing // FIXME: this shouldn't fail during name resolution either mod a { diff --git a/tests/ui/weird-exprs.rs b/tests/ui/weird-exprs.rs index 59b4bb8ef85..892b281357f 100644 --- a/tests/ui/weird-exprs.rs +++ b/tests/ui/weird-exprs.rs @@ -1,7 +1,6 @@ // run-pass #![feature(generators)] -#![feature(unboxed_closures, fn_traits)] #![allow(non_camel_case_types)] #![allow(dead_code)] @@ -17,6 +16,7 @@ extern crate core; use std::cell::Cell; use std::mem::swap; +use std::ops::Deref; // Just a grab bag of stuff that you wouldn't want to actually write. @@ -183,10 +183,10 @@ fn 𝚌𝚘𝚗𝚝𝚒𝚗𝚞𝚎() { fn function() { struct foo; - impl FnOnce<()> for foo { - type Output = foo; - extern "rust-call" fn call_once(self, _args: ()) -> Self::Output { - foo + impl Deref for foo { + type Target = fn() -> Self; + fn deref(&self) -> &Self::Target { + &((|| foo) as _) } } let foo = foo () ()() ()()() ()()()() ()()()()(); diff --git a/tests/ui/xcrate/xcrate-private-by-default.stderr b/tests/ui/xcrate/xcrate-private-by-default.stderr index 0bdd4002f40..25bbbf5f62a 100644 --- a/tests/ui/xcrate/xcrate-private-by-default.stderr +++ b/tests/ui/xcrate/xcrate-private-by-default.stderr @@ -62,7 +62,9 @@ error[E0603]: module `foo` is private --> $DIR/xcrate-private-by-default.rs:35:29 | LL | static_priv_by_default::foo::a; - | ^^^ private module + | ^^^ - static `a` is not publicly re-exported + | | + | private module | note: the module `foo` is defined here --> $DIR/auxiliary/static_priv_by_default.rs:12:1 @@ -74,7 +76,9 @@ error[E0603]: module `foo` is private --> $DIR/xcrate-private-by-default.rs:37:29 | LL | static_priv_by_default::foo::b; - | ^^^ private module + | ^^^ - function `b` is not publicly re-exported + | | + | private module | note: the module `foo` is defined here --> $DIR/auxiliary/static_priv_by_default.rs:12:1 @@ -86,7 +90,9 @@ error[E0603]: module `foo` is private --> $DIR/xcrate-private-by-default.rs:39:29 | LL | static_priv_by_default::foo::c; - | ^^^ private module + | ^^^ - unit struct `c` is not publicly re-exported + | | + | private module | note: the module `foo` is defined here --> $DIR/auxiliary/static_priv_by_default.rs:12:1 @@ -98,7 +104,9 @@ error[E0603]: module `foo` is private --> $DIR/xcrate-private-by-default.rs:41:35 | LL | foo::<static_priv_by_default::foo::d>(); - | ^^^ private module + | ^^^ - enum `d` is not publicly re-exported + | | + | private module | note: the module `foo` is defined here --> $DIR/auxiliary/static_priv_by_default.rs:12:1 @@ -110,7 +118,9 @@ error[E0603]: module `foo` is private --> $DIR/xcrate-private-by-default.rs:43:35 | LL | foo::<static_priv_by_default::foo::e>(); - | ^^^ private module + | ^^^ - type alias `e` is not publicly re-exported + | | + | private module | note: the module `foo` is defined here --> $DIR/auxiliary/static_priv_by_default.rs:12:1 |
