From 8071cbd73021a4e1b9edcbe8b4f47cca3f0cdf9e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 4 Nov 2024 07:58:26 +0100 Subject: [PATCH 01/22] Render extern blocks in file_structure --- .../crates/ide/src/file_structure.rs | 59 ++++++++++++++----- .../crates/rust-analyzer/src/lsp/to_proto.rs | 1 + 2 files changed, 45 insertions(+), 15 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs index 055080ad17b13..5ef65c209cabb 100644 --- a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs +++ b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs @@ -19,6 +19,7 @@ pub struct StructureNode { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum StructureNodeKind { SymbolKind(SymbolKind), + ExternBlock, Region, } @@ -158,6 +159,7 @@ fn structure_node(node: &SyntaxNode) -> Option { ast::Trait(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Trait)), ast::TraitAlias(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::TraitAlias)), ast::Module(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Module)), + ast::Macro(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)), ast::TypeAlias(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::TypeAlias)), ast::RecordField(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::Field)), ast::Const(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::Const)), @@ -205,7 +207,23 @@ fn structure_node(node: &SyntaxNode) -> Option { Some(node) }, - ast::Macro(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)), + ast::ExternBlock(it) => { + let mut label = "extern".to_owned(); + let abi = it.abi()?; + if let Some(abi) = abi.string_token() { + label.push(' '); + label.push_str(abi.text()); + } + Some(StructureNode { + parent: None, + label, + navigation_range: abi.syntax().text_range(), + node_range: it.syntax().text_range(), + kind: StructureNodeKind::ExternBlock, + detail: None, + deprecated: false, + }) + }, _ => None, } } @@ -327,6 +345,8 @@ fn f() {} fn g() {} } +extern "C" {} + fn let_statements() { let x = 42; let mut y = x; @@ -662,11 +682,20 @@ fn let_statements() { ), deprecated: false, }, + StructureNode { + parent: None, + label: "extern \"C\"", + navigation_range: 638..648, + node_range: 638..651, + kind: ExternBlock, + detail: None, + deprecated: false, + }, StructureNode { parent: None, label: "let_statements", - navigation_range: 641..655, - node_range: 638..798, + navigation_range: 656..670, + node_range: 653..813, kind: SymbolKind( Function, ), @@ -677,11 +706,11 @@ fn let_statements() { }, StructureNode { parent: Some( - 26, + 27, ), label: "x", - navigation_range: 668..669, - node_range: 664..675, + navigation_range: 683..684, + node_range: 679..690, kind: SymbolKind( Local, ), @@ -690,11 +719,11 @@ fn let_statements() { }, StructureNode { parent: Some( - 26, + 27, ), label: "mut y", - navigation_range: 684..689, - node_range: 680..694, + navigation_range: 699..704, + node_range: 695..709, kind: SymbolKind( Local, ), @@ -703,11 +732,11 @@ fn let_statements() { }, StructureNode { parent: Some( - 26, + 27, ), label: "Foo { .. }", - navigation_range: 703..725, - node_range: 699..738, + navigation_range: 718..740, + node_range: 714..753, kind: SymbolKind( Local, ), @@ -716,11 +745,11 @@ fn let_statements() { }, StructureNode { parent: Some( - 26, + 27, ), label: "_", - navigation_range: 788..789, - node_range: 784..796, + navigation_range: 803..804, + node_range: 799..811, kind: SymbolKind( Local, ), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs index d654dc3e7f4a1..c59e4699f27fd 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs @@ -88,6 +88,7 @@ pub(crate) fn structure_node_kind(kind: StructureNodeKind) -> lsp_types::SymbolK match kind { StructureNodeKind::SymbolKind(symbol) => symbol_kind(symbol), StructureNodeKind::Region => lsp_types::SymbolKind::NAMESPACE, + StructureNodeKind::ExternBlock => lsp_types::SymbolKind::NAMESPACE, } } From 5cbfb7422b09d46734f2a4a150fb581ede92d735 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 3 Nov 2024 16:29:35 +0100 Subject: [PATCH 02/22] Support new #[rustc_intrinsic] attribute and fallback bodies --- .../rust-analyzer/crates/hir-def/src/data.rs | 4 - .../crates/hir-expand/src/inert_attr_macro.rs | 13 ++ .../hir-ty/src/consteval/tests/intrinsics.rs | 97 ++++++------ .../hir-ty/src/diagnostics/decl_check.rs | 2 +- .../crates/hir-ty/src/mir/eval/shim.rs | 144 +++++++----------- .../rust-analyzer/crates/hir-ty/src/utils.rs | 22 +-- src/tools/rust-analyzer/crates/hir/src/lib.rs | 19 +-- .../crates/intern/src/symbol/symbols.rs | 6 +- .../crates/test-utils/src/minicore.rs | 10 +- 9 files changed, 143 insertions(+), 174 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs index 6d07dc8f9bebf..2a13f74aac710 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs @@ -13,7 +13,6 @@ use syntax::{ast, Parse}; use triomphe::Arc; use crate::{ - attr::Attrs, db::DefDatabase, expander::{Expander, Mark}, item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, MacroCall, ModItem, TreeId}, @@ -37,8 +36,6 @@ pub struct FunctionData { pub name: Name, pub params: Box<[TypeRefId]>, pub ret_type: TypeRefId, - // FIXME: why are these stored here? They should be accessed via the query - pub attrs: Attrs, pub visibility: RawVisibility, pub abi: Option, pub legacy_const_generics_indices: Option>>, @@ -115,7 +112,6 @@ impl FunctionData { .filter_map(|(_, param)| param.type_ref) .collect(), ret_type: func.ret_type, - attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()), visibility, abi: func.abi.clone(), legacy_const_generics_indices, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs index 5c25a55362e64..95dfe56ff5445 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs @@ -632,6 +632,19 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_safe_intrinsic, Normal, template!(Word), WarnFollowing, "the `#[rustc_safe_intrinsic]` attribute is used internally to mark intrinsics as safe" ), + rustc_attr!( + rustc_intrinsic, Normal, template!(Word), ErrorFollowing, + "the `#[rustc_intrinsic]` attribute is used to declare intrinsics with function bodies", + ), + rustc_attr!( + rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, + "#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen" + ), + rustc_attr!( + rustc_intrinsic_must_be_overridden, Normal, template!(Word), ErrorFollowing, + "the `#[rustc_intrinsic_must_be_overridden]` attribute is used to declare intrinsics without real bodies", + ), + rustc_attr!( rustc_deprecated_safe_2024, Normal, template!(Word), WarnFollowing, "the `#[rustc_safe_intrinsic]` marks functions as unsafe in Rust 2024", diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs index c5706172b20c4..c1ac7ae173b81 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs @@ -4,9 +4,8 @@ use super::*; fn size_of() { check_number( r#" - extern "rust-intrinsic" { - pub fn size_of() -> usize; - } + #[rustc_intrinsic] + pub fn size_of() -> usize; const GOAL: usize = size_of::(); "#, @@ -19,9 +18,8 @@ fn size_of_val() { check_number( r#" //- minicore: coerce_unsized - extern "rust-intrinsic" { - pub fn size_of_val(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn size_of_val(_: *const T) -> usize; struct X(i32, u8); @@ -32,9 +30,8 @@ fn size_of_val() { check_number( r#" //- minicore: coerce_unsized - extern "rust-intrinsic" { - pub fn size_of_val(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn size_of_val(_: *const T) -> usize; const GOAL: usize = { let it: &[i32] = &[1, 2, 3]; @@ -48,9 +45,8 @@ fn size_of_val() { //- minicore: coerce_unsized, transmute use core::mem::transmute; - extern "rust-intrinsic" { - pub fn size_of_val(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn size_of_val(_: *const T) -> usize; struct X { x: i64, @@ -70,9 +66,8 @@ fn size_of_val() { //- minicore: coerce_unsized, transmute use core::mem::transmute; - extern "rust-intrinsic" { - pub fn size_of_val(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn size_of_val(_: *const T) -> usize; struct X { x: i32, @@ -90,9 +85,8 @@ fn size_of_val() { check_number( r#" //- minicore: coerce_unsized, fmt, builtin_impls, dispatch_from_dyn - extern "rust-intrinsic" { - pub fn size_of_val(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn size_of_val(_: *const T) -> usize; const GOAL: usize = { let x: &i16 = &5; @@ -106,9 +100,8 @@ fn size_of_val() { check_number( r#" //- minicore: coerce_unsized - extern "rust-intrinsic" { - pub fn size_of_val(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn size_of_val(_: *const T) -> usize; const GOAL: usize = { size_of_val("salam") @@ -123,9 +116,8 @@ fn min_align_of_val() { check_number( r#" //- minicore: coerce_unsized - extern "rust-intrinsic" { - pub fn min_align_of_val(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn min_align_of_val(_: *const T) -> usize; struct X(i32, u8); @@ -136,9 +128,8 @@ fn min_align_of_val() { check_number( r#" //- minicore: coerce_unsized - extern "rust-intrinsic" { - pub fn min_align_of_val(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn min_align_of_val(_: *const T) -> usize; const GOAL: usize = { let x: &[i32] = &[1, 2, 3]; @@ -153,9 +144,8 @@ fn min_align_of_val() { fn type_name() { check_str( r#" - extern "rust-intrinsic" { - pub fn type_name() -> &'static str; - } + #[rustc_intrinsic] + pub fn type_name() -> &'static str; const GOAL: &str = type_name::(); "#, @@ -163,9 +153,8 @@ fn type_name() { ); check_str( r#" - extern "rust-intrinsic" { - pub fn type_name() -> &'static str; - } + #[rustc_intrinsic] + pub fn type_name() -> &'static str; mod mod1 { pub mod mod2 { @@ -183,9 +172,8 @@ fn type_name() { fn transmute() { check_number( r#" - extern "rust-intrinsic" { - pub fn transmute(e: T) -> U; - } + #[rustc_intrinsic] + pub fn transmute(e: T) -> U; const GOAL: i32 = transmute((1i16, 1i16)); "#, @@ -197,10 +185,10 @@ fn transmute() { fn read_via_copy() { check_number( r#" - extern "rust-intrinsic" { - pub fn read_via_copy(e: *const T) -> T; - pub fn volatile_load(e: *const T) -> T; - } + #[rustc_intrinsic] + pub fn read_via_copy(e: *const T) -> T; + #[rustc_intrinsic] + pub fn volatile_load(e: *const T) -> T; const GOAL: i32 = { let x = 2; @@ -399,9 +387,14 @@ fn discriminant_value() { fn likely() { check_number( r#" - extern "rust-intrinsic" { - pub fn likely(b: bool) -> bool; - pub fn unlikely(b: bool) -> bool; + #[rustc_intrinsic] + pub const fn likely(b: bool) -> bool { + b + } + + #[rustc_intrinsic] + pub const fn unlikely(b: bool) -> bool { + b } const GOAL: bool = likely(true) && unlikely(true) && !likely(false) && !unlikely(false); @@ -704,9 +697,8 @@ fn rotate() { ); check_number( r#" - extern "rust-intrinsic" { - pub fn rotate_right(x: T, y: T) -> T; - } + #[rustc_intrinsic] + pub fn rotate_right(x: T, y: T) -> T; const GOAL: i32 = rotate_right(10006016, 1020315); "#, @@ -721,9 +713,8 @@ fn simd() { pub struct i8x16( i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8, ); - extern "platform-intrinsic" { - pub fn simd_bitmask(x: T) -> U; - } + #[rustc_intrinsic] + pub fn simd_bitmask(x: T) -> U; const GOAL: u16 = simd_bitmask(i8x16( 0, 1, 0, 0, 2, 255, 100, 0, 50, 0, 1, 1, 0, 0, 0, 0 )); @@ -735,10 +726,10 @@ fn simd() { pub struct i8x16( i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8, ); - extern "platform-intrinsic" { - pub fn simd_lt(x: T, y: T) -> U; - pub fn simd_bitmask(x: T) -> U; - } + #[rustc_intrinsic] + pub fn simd_lt(x: T, y: T) -> U; + #[rustc_intrinsic] + pub fn simd_bitmask(x: T) -> U; const GOAL: u16 = simd_bitmask(simd_lt::( i8x16( -105, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs index c9ab0acc0849e..4991d173b9c42 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs @@ -201,7 +201,7 @@ impl<'a> DeclValidator<'a> { // Don't run the lint on extern "[not Rust]" fn items with the // #[no_mangle] attribute. - let no_mangle = data.attrs.by_key(&sym::no_mangle).exists(); + let no_mangle = self.db.attrs(func.into()).by_key(&sym::no_mangle).exists(); if no_mangle && data.abi.as_ref().is_some_and(|abi| *abi != sym::Rust) { cov_mark::hit!(extern_func_no_mangle_ignored); } else { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index 0cdad74a4f6c1..0a78f4a5b24b7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -9,7 +9,7 @@ use hir_def::{ resolver::HasResolver, }; use hir_expand::name::Name; -use intern::sym; +use intern::{sym, Symbol}; use crate::{ error_lifetime, @@ -54,49 +54,32 @@ impl Evaluator<'_> { } let function_data = self.db.function_data(def); - let is_intrinsic = match &function_data.abi { - Some(abi) => *abi == sym::rust_dash_intrinsic, - None => match def.lookup(self.db.upcast()).container { - hir_def::ItemContainerId::ExternBlockId(block) => { - let id = block.lookup(self.db.upcast()).id; - id.item_tree(self.db.upcast())[id.value].abi.as_ref() - == Some(&sym::rust_dash_intrinsic) - } - _ => false, - }, - }; + let attrs = self.db.attrs(def.into()); + let is_intrinsic = attrs.by_key(&sym::rustc_intrinsic).exists() + // Keep this around for a bit until extern "rustc-intrinsic" abis are no longer used + || (match &function_data.abi { + Some(abi) => *abi == sym::rust_dash_intrinsic, + None => match def.lookup(self.db.upcast()).container { + hir_def::ItemContainerId::ExternBlockId(block) => { + let id = block.lookup(self.db.upcast()).id; + id.item_tree(self.db.upcast())[id.value].abi.as_ref() + == Some(&sym::rust_dash_intrinsic) + } + _ => false, + }, + }); + if is_intrinsic { - self.exec_intrinsic( + return self.exec_intrinsic( function_data.name.as_str(), args, generic_args, destination, locals, span, - )?; - return Ok(true); - } - let is_platform_intrinsic = match &function_data.abi { - Some(abi) => *abi == sym::platform_dash_intrinsic, - None => match def.lookup(self.db.upcast()).container { - hir_def::ItemContainerId::ExternBlockId(block) => { - let id = block.lookup(self.db.upcast()).id; - id.item_tree(self.db.upcast())[id.value].abi.as_ref() - == Some(&sym::platform_dash_intrinsic) - } - _ => false, - }, - }; - if is_platform_intrinsic { - self.exec_platform_intrinsic( - function_data.name.as_str(), - args, - generic_args, - destination, - locals, - span, - )?; - return Ok(true); + !function_data.has_body() + || attrs.by_key(&sym::rustc_intrinsic_must_be_overridden).exists(), + ); } let is_extern_c = match def.lookup(self.db.upcast()).container { hir_def::ItemContainerId::ExternBlockId(block) => { @@ -106,27 +89,25 @@ impl Evaluator<'_> { _ => false, }; if is_extern_c { - self.exec_extern_c( - function_data.name.as_str(), - args, - generic_args, - destination, - locals, - span, - )?; - return Ok(true); + return self + .exec_extern_c( + function_data.name.as_str(), + args, + generic_args, + destination, + locals, + span, + ) + .map(|()| true); } - let alloc_fn = function_data - .attrs - .iter() - .filter_map(|it| it.path().as_ident()) - .map(|it| it.as_str()) - .find(|it| { + + let alloc_fn = + attrs.iter().filter_map(|it| it.path().as_ident()).map(|it| it.symbol()).find(|it| { [ - "rustc_allocator", - "rustc_deallocator", - "rustc_reallocator", - "rustc_allocator_zeroed", + &sym::rustc_allocator, + &sym::rustc_deallocator, + &sym::rustc_reallocator, + &sym::rustc_allocator_zeroed, ] .contains(it) }); @@ -270,12 +251,12 @@ impl Evaluator<'_> { fn exec_alloc_fn( &mut self, - alloc_fn: &str, + alloc_fn: &Symbol, args: &[IntervalAndTy], destination: Interval, ) -> Result<()> { match alloc_fn { - "rustc_allocator_zeroed" | "rustc_allocator" => { + _ if *alloc_fn == sym::rustc_allocator_zeroed || *alloc_fn == sym::rustc_allocator => { let [size, align] = args else { return Err(MirEvalError::InternalError( "rustc_allocator args are not provided".into(), @@ -286,8 +267,8 @@ impl Evaluator<'_> { let result = self.heap_allocate(size, align)?; destination.write_from_bytes(self, &result.to_bytes())?; } - "rustc_deallocator" => { /* no-op for now */ } - "rustc_reallocator" => { + _ if *alloc_fn == sym::rustc_deallocator => { /* no-op for now */ } + _ if *alloc_fn == sym::rustc_reallocator => { let [ptr, old_size, align, new_size] = args else { return Err(MirEvalError::InternalError( "rustc_allocator args are not provided".into(), @@ -603,21 +584,6 @@ impl Evaluator<'_> { } } - fn exec_platform_intrinsic( - &mut self, - name: &str, - args: &[IntervalAndTy], - generic_args: &Substitution, - destination: Interval, - locals: &Locals, - span: MirSpan, - ) -> Result<()> { - if let Some(name) = name.strip_prefix("simd_") { - return self.exec_simd_intrinsic(name, args, generic_args, destination, locals, span); - } - not_supported!("unknown platform intrinsic {name}"); - } - fn exec_intrinsic( &mut self, name: &str, @@ -626,9 +592,17 @@ impl Evaluator<'_> { destination: Interval, locals: &Locals, span: MirSpan, - ) -> Result<()> { + needs_override: bool, + ) -> Result { if let Some(name) = name.strip_prefix("atomic_") { - return self.exec_atomic_intrinsic(name, args, generic_args, destination, locals, span); + return self + .exec_atomic_intrinsic(name, args, generic_args, destination, locals, span) + .map(|()| true); + } + if let Some(name) = name.strip_prefix("simd_") { + return self + .exec_simd_intrinsic(name, args, generic_args, destination, locals, span) + .map(|()| true); } // FIXME(#17451): Add `f16` and `f128` intrinsics. if let Some(name) = name.strip_suffix("f64") { @@ -701,7 +675,7 @@ impl Evaluator<'_> { } _ => not_supported!("unknown f64 intrinsic {name}"), }; - return destination.write_from_bytes(self, &result.to_le_bytes()); + return destination.write_from_bytes(self, &result.to_le_bytes()).map(|()| true); } if let Some(name) = name.strip_suffix("f32") { let result = match name { @@ -773,7 +747,7 @@ impl Evaluator<'_> { } _ => not_supported!("unknown f32 intrinsic {name}"), }; - return destination.write_from_bytes(self, &result.to_le_bytes()); + return destination.write_from_bytes(self, &result.to_le_bytes()).map(|()| true); } match name { "size_of" => { @@ -1146,12 +1120,6 @@ impl Evaluator<'_> { }; destination.write_from_interval(self, arg.interval) } - "likely" | "unlikely" => { - let [arg] = args else { - return Err(MirEvalError::InternalError("likely arg is not provided".into())); - }; - destination.write_from_interval(self, arg.interval) - } "ctpop" => { let [arg] = args else { return Err(MirEvalError::InternalError("ctpop arg is not provided".into())); @@ -1296,7 +1264,7 @@ impl Evaluator<'_> { None, span, )?; - return Ok(()); + return Ok(true); } } not_supported!("FnOnce was not available for executing const_eval_select"); @@ -1349,8 +1317,10 @@ impl Evaluator<'_> { self.write_memory_using_ref(dst, size)?.fill(val); Ok(()) } - _ => not_supported!("unknown intrinsic {name}"), + _ if needs_override => not_supported!("intrinsic {name} is not implemented"), + _ => return Ok(false), } + .map(|()| true) } fn size_align_of_unsized( 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 0a436ff2b41ab..7429ce3c73e0c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -259,25 +259,25 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool { return true; } + let is_intrinsic = db.attrs(func.into()).by_key(&sym::rustc_intrinsic).exists() + || data.abi.as_ref() == Some(&sym::rust_dash_intrinsic); + let loc = func.lookup(db.upcast()); match loc.container { hir_def::ItemContainerId::ExternBlockId(block) => { - // Function in an `extern` block are always unsafe to call, except when - // it is marked as `safe` or it has `"rust-intrinsic"` ABI there are a - // few exceptions. - let id = block.lookup(db.upcast()).id; - - let is_intrinsic = - id.item_tree(db.upcast())[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic); - - if is_intrinsic { + if is_intrinsic || { + let id = block.lookup(db.upcast()).id; + id.item_tree(db.upcast())[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic) + } { // Intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute - !data.attrs.by_key(&sym::rustc_safe_intrinsic).exists() + !db.attrs(func.into()).by_key(&sym::rustc_safe_intrinsic).exists() } else { - // Extern items without `safe` modifier are always unsafe + // Function in an `extern` block are always unsafe to call, except when + // it is marked as `safe`. !data.is_safe() } } + _ if is_intrinsic => !db.attrs(func.into()).by_key(&sym::rustc_safe_intrinsic).exists(), _ => false, } } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index ebd84fd2be2a6..8c3b7a6d3cf51 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -2246,35 +2246,33 @@ impl Function { /// Does this function have `#[test]` attribute? pub fn is_test(self, db: &dyn HirDatabase) -> bool { - db.function_data(self.id).attrs.is_test() + db.attrs(self.id.into()).is_test() } /// is this a `fn main` or a function with an `export_name` of `main`? pub fn is_main(self, db: &dyn HirDatabase) -> bool { - let data = db.function_data(self.id); - data.attrs.export_name() == Some(&sym::main) - || self.module(db).is_crate_root() && data.name == sym::main + db.attrs(self.id.into()).export_name() == Some(&sym::main) + || self.module(db).is_crate_root() && db.function_data(self.id).name == sym::main } /// Is this a function with an `export_name` of `main`? pub fn exported_main(self, db: &dyn HirDatabase) -> bool { - let data = db.function_data(self.id); - data.attrs.export_name() == Some(&sym::main) + db.attrs(self.id.into()).export_name() == Some(&sym::main) } /// Does this function have the ignore attribute? pub fn is_ignore(self, db: &dyn HirDatabase) -> bool { - db.function_data(self.id).attrs.is_ignore() + db.attrs(self.id.into()).is_ignore() } /// Does this function have `#[bench]` attribute? pub fn is_bench(self, db: &dyn HirDatabase) -> bool { - db.function_data(self.id).attrs.is_bench() + db.attrs(self.id.into()).is_bench() } /// Is this function marked as unstable with `#[feature]` attribute? pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { - db.function_data(self.id).attrs.is_unstable() + db.attrs(self.id.into()).is_unstable() } pub fn is_unsafe_to_call(self, db: &dyn HirDatabase) -> bool { @@ -2289,8 +2287,7 @@ impl Function { } pub fn as_proc_macro(self, db: &dyn HirDatabase) -> Option { - let function_data = db.function_data(self.id); - let attrs = &function_data.attrs; + let attrs = db.attrs(self.id.into()); // FIXME: Store this in FunctionData flags? if !(attrs.is_proc_macro() || attrs.is_proc_macro_attribute() diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index aecafb444c30e..865518fe941e8 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -392,18 +392,22 @@ define_symbols! { rust_2024, rust_analyzer, Rust, + rustc_allocator_zeroed, + rustc_allocator, rustc_allow_incoherent_impl, rustc_builtin_macro, rustc_coherence_is_core, rustc_const_panic_str, + rustc_deallocator, rustc_deprecated_safe_2024, rustc_has_incoherent_inherent_impls, - rustc_intrinsic, rustc_intrinsic_must_be_overridden, + rustc_intrinsic, rustc_layout_scalar_valid_range_end, rustc_layout_scalar_valid_range_start, rustc_legacy_const_generics, rustc_macro_transparency, + rustc_reallocator, rustc_reservation_impl, rustc_safe_intrinsic, rustc_skip_array_during_method_dispatch, 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 67629fcf7cc5e..07767d5ae9f66 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -370,15 +370,13 @@ pub mod mem { // endregion:drop // region:transmute - extern "rust-intrinsic" { - pub fn transmute(src: Src) -> Dst; - } + #[rustc_intrinsic] + pub fn transmute(src: Src) -> Dst; // endregion:transmute // region:size_of - extern "rust-intrinsic" { - pub fn size_of() -> usize; - } + #[rustc_intrinsic] + pub fn size_of() -> usize; // endregion:size_of // region:discriminant From 1330cd1888ca1cb7ae2785dc1a18d55d3a3f21b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 4 Nov 2024 15:23:05 +0200 Subject: [PATCH 03/22] Don't try to auto-publish text-edit --- src/tools/rust-analyzer/.github/workflows/autopublish.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/rust-analyzer/.github/workflows/autopublish.yaml b/src/tools/rust-analyzer/.github/workflows/autopublish.yaml index e0135a0269a3a..5258d9ddd3ad0 100644 --- a/src/tools/rust-analyzer/.github/workflows/autopublish.yaml +++ b/src/tools/rust-analyzer/.github/workflows/autopublish.yaml @@ -53,7 +53,6 @@ jobs: cargo workspaces rename --from project-model project_model cargo workspaces rename --from test-fixture test_fixture cargo workspaces rename --from test-utils test_utils - cargo workspaces rename --from text-edit text_edit # Remove library crates from the workspaces so we don't auto-publish them as well sed -i 's/ "lib\/\*",//' ./Cargo.toml cargo workspaces rename ra_ap_%n From 59ee3bd9485db9e1d75671d2c599aa46ed51b2ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 4 Nov 2024 21:35:10 +0200 Subject: [PATCH 04/22] Enable triagebot transfer feature --- src/tools/rust-analyzer/triagebot.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/rust-analyzer/triagebot.toml b/src/tools/rust-analyzer/triagebot.toml index d62adb9144bae..1138035d0e82e 100644 --- a/src/tools/rust-analyzer/triagebot.toml +++ b/src/tools/rust-analyzer/triagebot.toml @@ -19,3 +19,5 @@ exclude_titles = [ # exclude syncs from subtree in rust-lang/rust "sync from rust", ] labels = ["has-merge-commits", "S-waiting-on-author"] + +[transfer] From 80df05b8b88a8c2f4371169d3d55528fe1063c91 Mon Sep 17 00:00:00 2001 From: Vincent Esche Date: Wed, 6 Nov 2024 09:53:56 +0100 Subject: [PATCH 05/22] =?UTF-8?q?Add=20`pub=20fn=20all=5Fsupertraits(?= =?UTF-8?q?=E2=80=A6)`=20HIR-level=20method=20to=20`hir::Trait`=20type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tools/rust-analyzer/crates/hir/src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 8c3b7a6d3cf51..00a46daa54e7c 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -2704,6 +2704,11 @@ impl Trait { db.trait_data(self.id).name.clone() } + pub fn all_supertraits(self, db: &dyn HirDatabase) -> Vec { + let traits = all_super_traits(db.upcast(), self.into()); + traits.iter().map(|tr| Trait::from(*tr)).collect() + } + pub fn items(self, db: &dyn HirDatabase) -> Vec { db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect() } From fa393dd9d8e0427e75b58ba3561cc1d58004bba1 Mon Sep 17 00:00:00 2001 From: Vincent Esche Date: Wed, 6 Nov 2024 09:37:53 +0100 Subject: [PATCH 06/22] =?UTF-8?q?Refactor=20`hir::Trait`'s=20existing=20`i?= =?UTF-8?q?tems=5Fwith=5Fsupertraits(=E2=80=A6)`=20method=20based=20on=20n?= =?UTF-8?q?ew=20`all=5Fsupertraits(=E2=80=A6)`=20method?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tools/rust-analyzer/crates/hir/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 00a46daa54e7c..bfe9f3bd74efa 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -2714,8 +2714,7 @@ impl Trait { } pub fn items_with_supertraits(self, db: &dyn HirDatabase) -> Vec { - let traits = all_super_traits(db.upcast(), self.into()); - traits.iter().flat_map(|tr| Trait::from(*tr).items(db)).collect() + self.all_supertraits(db).into_iter().flat_map(|tr| tr.items(db)).collect() } pub fn is_auto(self, db: &dyn HirDatabase) -> bool { From de30d7dc37239209827cdb7283e017863cdc0bd2 Mon Sep 17 00:00:00 2001 From: Vincent Esche Date: Wed, 6 Nov 2024 09:52:49 +0100 Subject: [PATCH 07/22] Add `pub fn direct_super_traits(db, trait_id)` to `hir_ty` crate --- src/tools/rust-analyzer/crates/hir-ty/src/lib.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/utils.rs | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 9c1d8bcf36f02..22e7b1d920f60 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -98,7 +98,7 @@ pub use mapping::{ }; pub use method_resolution::check_orphan_rules; pub use traits::TraitEnvironment; -pub use utils::{all_super_traits, is_fn_unsafe_to_call}; +pub use utils::{all_super_traits, direct_super_traits, is_fn_unsafe_to_call}; pub use chalk_ir::{ cast::Cast, 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 7429ce3c73e0c..28bda1e10e58a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -43,6 +43,17 @@ pub(crate) fn fn_traits( .flat_map(|it| it.as_trait()) } +/// Returns an iterator over the direct super traits (including the trait itself). +pub fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> { + let mut result = smallvec![trait_]; + direct_super_traits_cb(db, trait_, |tt| { + if !result.contains(&tt) { + result.push(tt); + } + }); + result +} + /// Returns an iterator over the whole super trait hierarchy (including the /// trait itself). pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> { @@ -54,7 +65,7 @@ pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[Trai while let Some(&t) = result.get(i) { // yeah this is quadratic, but trait hierarchies should be flat // enough that this doesn't matter - direct_super_traits(db, t, |tt| { + direct_super_traits_cb(db, t, |tt| { if !result.contains(&tt) { result.push(tt); } @@ -153,7 +164,7 @@ impl Iterator for ClauseElaborator<'_> { } } -fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) { +fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) { let resolver = trait_.resolver(db); let generic_params = db.generic_params(trait_.into()); let trait_self = generic_params.trait_self_param(); From d5dec8ab035f50af3a34c30f90350ef3d3f2cae0 Mon Sep 17 00:00:00 2001 From: Vincent Esche Date: Wed, 6 Nov 2024 09:53:11 +0100 Subject: [PATCH 08/22] =?UTF-8?q?Add=20`direct=5Fsupertraits(=E2=80=A6)`?= =?UTF-8?q?=20HIR-level=20method=20to=20`hir::Trait`=20type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tools/rust-analyzer/crates/hir/src/lib.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index bfe9f3bd74efa..c9498b3aead7c 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -68,7 +68,7 @@ use hir_ty::{ all_super_traits, autoderef, check_orphan_rules, consteval::{try_const_usize, unknown_const_as_generic, ConstExt}, diagnostics::BodyValidationDiagnostic, - error_lifetime, known_const_to_ast, + direct_super_traits, error_lifetime, known_const_to_ast, layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding}, method_resolution, mir::{interpret_mir, MutBorrowKind}, @@ -2704,6 +2704,11 @@ impl Trait { db.trait_data(self.id).name.clone() } + pub fn direct_supertraits(self, db: &dyn HirDatabase) -> Vec { + let traits = direct_super_traits(db.upcast(), self.into()); + traits.iter().map(|tr| Trait::from(*tr)).collect() + } + pub fn all_supertraits(self, db: &dyn HirDatabase) -> Vec { let traits = all_super_traits(db.upcast(), self.into()); traits.iter().map(|tr| Trait::from(*tr)).collect() From cd6ddcaf42ee3d66379bd205b82541957ed82e48 Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Wed, 6 Nov 2024 15:00:59 -0800 Subject: [PATCH 09/22] editors/code: Change minimum VS Code from 1.78 to 1.83 It's been a year since we last bumped this (see #15904), and VS Code 1.83 is the first version that supports LSP 3.17.5 (via vscode-languageclient 9.0.1). https://code.visualstudio.com/updates/v1_83#_language-server-protocol --- .../editors/code/package-lock.json | 44 +++++++++---------- .../rust-analyzer/editors/code/package.json | 6 +-- .../rust-analyzer/editors/code/src/client.ts | 2 + 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json index 10b633511d3e0..6027f813311c9 100644 --- a/src/tools/rust-analyzer/editors/code/package-lock.json +++ b/src/tools/rust-analyzer/editors/code/package-lock.json @@ -13,12 +13,12 @@ "anser": "^2.1.1", "d3": "^7.8.5", "d3-graphviz": "^5.0.2", - "vscode-languageclient": "^8.1.0" + "vscode-languageclient": "^9.0.1" }, "devDependencies": { "@tsconfig/strictest": "^2.0.1", "@types/node": "~16.11.7", - "@types/vscode": "~1.78.1", + "@types/vscode": "~1.83", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "@vscode/test-electron": "^2.3.8", @@ -32,7 +32,7 @@ "typescript": "^5.6.0" }, "engines": { - "vscode": "^1.78.0" + "vscode": "^1.83.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -880,9 +880,9 @@ "dev": true }, "node_modules/@types/vscode": { - "version": "1.78.1", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.78.1.tgz", - "integrity": "sha512-wEA+54axejHu7DhcUfnFBan1IqFD1gBDxAFz8LoX06NbNDMRJv/T6OGthOs52yZccasKfN588EyffHWABkR0fg==", + "version": "1.83.3", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.83.3.tgz", + "integrity": "sha512-ZPp5+OQNYrCSFoT4jWOZKdcuXijj+JdN2BJNDhWH4pPbVL6PRQycG9NT8C4a94oul1tFMbkVbXXa9HasI7cLUg==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { @@ -5059,24 +5059,24 @@ } }, "node_modules/vscode-jsonrpc": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0.tgz", - "integrity": "sha512-6TDy/abTQk+zDGYazgbIPc+4JoXdwC8NHU9Pbn4UJP1fehUyZmM4RHp5IthX7A6L5KS30PRui+j+tbbMMMafdw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", "engines": { "node": ">=14.0.0" } }, "node_modules/vscode-languageclient": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.1.0.tgz", - "integrity": "sha512-GL4QdbYUF/XxQlAsvYWZRV3V34kOkpRlvV60/72ghHfsYFnS/v2MANZ9P6sHmxFcZKOse8O+L9G7Czg0NUWing==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-9.0.1.tgz", + "integrity": "sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==", "dependencies": { "minimatch": "^5.1.0", "semver": "^7.3.7", - "vscode-languageserver-protocol": "3.17.3" + "vscode-languageserver-protocol": "3.17.5" }, "engines": { - "vscode": "^1.67.0" + "vscode": "^1.82.0" } }, "node_modules/vscode-languageclient/node_modules/brace-expansion": { @@ -5099,18 +5099,18 @@ } }, "node_modules/vscode-languageserver-protocol": { - "version": "3.17.3", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.3.tgz", - "integrity": "sha512-924/h0AqsMtA5yK22GgMtCYiMdCOtWTSGgUOkgEDX+wk2b0x4sAfLiO4NxBxqbiVtz7K7/1/RgVrVI0NClZwqA==", + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", "dependencies": { - "vscode-jsonrpc": "8.1.0", - "vscode-languageserver-types": "3.17.3" + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" } }, "node_modules/vscode-languageserver-types": { - "version": "3.17.3", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.3.tgz", - "integrity": "sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA==" + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==" }, "node_modules/which": { "version": "2.0.2", diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index ccc8c0e38423b..942d47c928374 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -27,7 +27,7 @@ } }, "engines": { - "vscode": "^1.78.0" + "vscode": "^1.83.0" }, "enabledApiProposals": [], "scripts": { @@ -49,12 +49,12 @@ "anser": "^2.1.1", "d3": "^7.8.5", "d3-graphviz": "^5.0.2", - "vscode-languageclient": "^8.1.0" + "vscode-languageclient": "^9.0.1" }, "devDependencies": { "@tsconfig/strictest": "^2.0.1", "@types/node": "~16.11.7", - "@types/vscode": "~1.78.1", + "@types/vscode": "~1.83", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "@vscode/test-electron": "^2.3.8", diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts index bf58112916b60..eac7b849fdb97 100644 --- a/src/tools/rust-analyzer/editors/code/src/client.ts +++ b/src/tools/rust-analyzer/editors/code/src/client.ts @@ -350,6 +350,7 @@ class ExperimentalFeatures implements lc.StaticFeature { _documentSelector: lc.DocumentSelector | undefined, ): void {} dispose(): void {} + clear(): void {} } class OverrideFeatures implements lc.StaticFeature { @@ -369,6 +370,7 @@ class OverrideFeatures implements lc.StaticFeature { _documentSelector: lc.DocumentSelector | undefined, ): void {} dispose(): void {} + clear(): void {} } function isCodeActionWithoutEditsAndCommands(value: any): boolean { From 902a2c5060a84c665474149bf3d9f29963690687 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Thu, 7 Nov 2024 23:00:29 +0900 Subject: [PATCH 10/22] minor: Rename `dyn compatible` to `dyn-compatible` --- src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs | 3 ++- .../rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs | 2 +- .../crates/hir-ty/src/dyn_compatibility/tests.rs | 2 +- src/tools/rust-analyzer/crates/ide/src/hover/render.rs | 6 +++--- src/tools/rust-analyzer/crates/ide/src/hover/tests.rs | 4 ++-- 5 files changed, 9 insertions(+), 8 deletions(-) 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 05cd7bd37b4b0..53795c0b600b8 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 @@ -381,8 +381,9 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { TyKind::Error.intern(Interner) } + // object safety was renamed to dyn-compatibility but still remains here in chalk. + // This will be removed since we are going to migrate to next-gen trait solver. fn is_object_safe(&self, trait_id: chalk_ir::TraitId) -> bool { - // FIXME: When cargo is updated, change to dyn_compatibility let trait_ = from_chalk_trait_id(trait_id); crate::dyn_compatibility::dyn_compatibility(self.db, trait_).is_none() } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index 3d21785a70a34..fadf8aca99822 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -472,7 +472,7 @@ fn receiver_is_dispatchable( return false; }; - // `self: Self` can't be dispatched on, but this is already considered dyn compatible + // `self: Self` can't be dispatched on, but this is already considered dyn-compatible // See rustc's comment on https://github.com/rust-lang/rust/blob/3f121b9461cce02a703a0e7e450568849dfaa074/compiler/rustc_trait_selection/src/traits/object_safety.rs#L433-L437 if sig .skip_binders() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs index 3f3e68eeb1c28..8a56bd28b598b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs @@ -66,7 +66,7 @@ fn check_dyn_compatibility<'a>( }); ControlFlow::Continue(()) }); - assert_eq!(osvs, expected, "Dyn Compatibility violations for `{name}` do not match;"); + assert_eq!(osvs, expected, "dyn-compatibility violations for `{name}` do not match;"); } let remains: Vec<_> = expected.keys().collect(); diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index 51a77283459aa..e9857e51225ef 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -1003,10 +1003,10 @@ fn render_dyn_compatibility( safety: Option, ) { let Some(osv) = safety else { - buf.push_str("Is Dyn compatible"); + buf.push_str("Is dyn-compatible"); return; }; - buf.push_str("Is not Dyn compatible due to "); + buf.push_str("Is not dyn-compatible due to "); match osv { DynCompatibilityViolation::SizedSelf => { buf.push_str("having a `Self: Sized` bound"); @@ -1049,7 +1049,7 @@ fn render_dyn_compatibility( } DynCompatibilityViolation::HasNonCompatibleSuperTrait(super_trait) => { let name = hir::Trait::from(super_trait).name(db); - format_to!(buf, "having a dyn incompatible supertrait `{}`", name.as_str()); + format_to!(buf, "having a dyn-incompatible supertrait `{}`", name.as_str()); } } } 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 1fad3d6bd6f1d..448bcd22d61e4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -9371,7 +9371,7 @@ trait Compat$0 {} --- - Is Dyn compatible + Is dyn-compatible "#]], ); check( @@ -9393,7 +9393,7 @@ trait UnCompat$0 { --- - Is not Dyn compatible due to having a method `f` that is not dispatchable due to missing a receiver + Is not dyn-compatible due to having a method `f` that is not dispatchable due to missing a receiver "#]], ); check( From 01726389fb7f28c2ba253f06cdb087f8e422fd41 Mon Sep 17 00:00:00 2001 From: Sam Estep Date: Thu, 7 Nov 2024 11:49:22 -0500 Subject: [PATCH 11/22] Delete design label from list --- src/tools/rust-analyzer/docs/dev/README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/tools/rust-analyzer/docs/dev/README.md b/src/tools/rust-analyzer/docs/dev/README.md index 12e6d829a089e..0d47ff09dcc2a 100644 --- a/src/tools/rust-analyzer/docs/dev/README.md +++ b/src/tools/rust-analyzer/docs/dev/README.md @@ -47,10 +47,6 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer Each triaged issue should have one of these labels. * [fun](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3Afun) is for cool, but probably hard stuff. -* [Design](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%Design) - is for moderate/large scale architecture discussion. - Also a kind of fun. - These issues should generally include a link to a Zulip discussion thread. # Code Style & Review Process From ef8a0c0016624df1142f838821f84558ebe6c740 Mon Sep 17 00:00:00 2001 From: Master-Hash Date: Fri, 8 Nov 2024 08:33:32 +0100 Subject: [PATCH 12/22] editors/code: Match supported debug engines in config with actual supported ones --- src/tools/rust-analyzer/editors/code/package.json | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 942d47c928374..b868622b3a520 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -490,15 +490,19 @@ "type": "string", "enum": [ "auto", + "llvm-vs-code-extensions.lldb-dap", "vadimcn.vscode-lldb", - "ms-vscode.cpptools" + "ms-vscode.cpptools", + "webfreak.debug" ], "default": "auto", "description": "Preferred debug engine.", "markdownEnumDescriptions": [ - "First try to use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb), if it's not installed try to use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools).", + "Use the first available extension out of [LLDB DAP](https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.lldb-dap), [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb), [C/C++ for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools), and [Native Debug](https://marketplace.visualstudio.com/items?itemName=webfreak.debug).", + "Use [LLDB DAP](https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.lldb-dap)", "Use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)", - "Use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)" + "Use [C/C++ for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)", + "Use [Native Debug](https://marketplace.visualstudio.com/items?itemName=webfreak.debug)" ] }, "rust-analyzer.debug.sourceFileMap": { From 29f84262a41b259b1f62ff39b9567c67e5787406 Mon Sep 17 00:00:00 2001 From: Sam Estep Date: Sun, 10 Nov 2024 13:34:26 -0500 Subject: [PATCH 13/22] Replace with C-Architecture --- src/tools/rust-analyzer/docs/dev/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tools/rust-analyzer/docs/dev/README.md b/src/tools/rust-analyzer/docs/dev/README.md index 0d47ff09dcc2a..cd0f49174cdc3 100644 --- a/src/tools/rust-analyzer/docs/dev/README.md +++ b/src/tools/rust-analyzer/docs/dev/README.md @@ -47,6 +47,10 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer Each triaged issue should have one of these labels. * [fun](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3Afun) is for cool, but probably hard stuff. +* [C-Architecture](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aissue%20state%3Aopen%20label%3AC-Architecture) + is for moderate/large scale architecture discussion. + Also a kind of fun. + These issues should generally include a link to a Zulip discussion thread. # Code Style & Review Process From fb26ba88f8de15e1980ea0f42ab27880ac81b332 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Mon, 11 Nov 2024 00:05:17 -0800 Subject: [PATCH 14/22] Generalize `NonNull::from_raw_parts` per ACP362 I did the raw pointers in 125701, but apparently forgot `NonNull`. --- library/core/src/ptr/non_null.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index ad24e50aa15d5..b69f8a4b9d3ea 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -251,7 +251,7 @@ impl NonNull { #[unstable(feature = "ptr_metadata", issue = "81513")] #[inline] pub const fn from_raw_parts( - data_pointer: NonNull<()>, + data_pointer: NonNull, metadata: ::Metadata, ) -> NonNull { // SAFETY: The result of `ptr::from::raw_parts_mut` is non-null because `data_pointer` is. From e04acff14ffffabd382323a5a7bc673965a66700 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 5 Nov 2024 17:02:13 -0800 Subject: [PATCH 15/22] Feature gate yield expressions not in 2024 --- compiler/rustc_ast_passes/src/feature_gate.rs | 15 +++++-- .../feature-gate-coroutines.e2024.stderr | 42 ++++++++++++++++++- .../feature-gates/feature-gate-coroutines.rs | 8 ++-- 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index d646150a620cd..9642c83efa24c 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -522,9 +522,18 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { "consider removing `for<...>`" ); gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental"); - for &span in spans.get(&sym::yield_expr).iter().copied().flatten() { - if !span.at_least_rust_2024() { - gate!(&visitor, coroutines, span, "yield syntax is experimental"); + // yield can be enabled either by `coroutines` or `gen_blocks` + if let Some(spans) = spans.get(&sym::yield_expr) { + for span in spans { + if (!visitor.features.coroutines() && !span.allows_unstable(sym::coroutines)) + && (!visitor.features.gen_blocks() && !span.allows_unstable(sym::gen_blocks)) + { + #[allow(rustc::untranslatable_diagnostic)] + // Don't know which of the two features to include in the + // error message, so I am arbitrarily picking one. + feature_err(&visitor.sess, sym::coroutines, *span, "yield syntax is experimental") + .emit(); + } } } gate_all!(gen_blocks, "gen blocks are experimental"); diff --git a/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr b/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr index 3bb48e4a37a4a..032d7adf77ab8 100644 --- a/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr +++ b/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr @@ -8,6 +8,46 @@ LL | yield true; = help: add `#![feature(coroutines)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: yield syntax is experimental + --> $DIR/feature-gate-coroutines.rs:10:16 + | +LL | let _ = || yield true; + | ^^^^^^^^^^ + | + = note: see issue #43122 for more information + = help: add `#![feature(coroutines)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: yield syntax is experimental + --> $DIR/feature-gate-coroutines.rs:18:5 + | +LL | yield; + | ^^^^^ + | + = note: see issue #43122 for more information + = help: add `#![feature(coroutines)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: yield syntax is experimental + --> $DIR/feature-gate-coroutines.rs:19:5 + | +LL | yield 0; + | ^^^^^^^ + | + = note: see issue #43122 for more information + = help: add `#![feature(coroutines)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: yield syntax is experimental + --> $DIR/feature-gate-coroutines.rs:5:5 + | +LL | yield true; + | ^^^^^^^^^^ + | + = note: see issue #43122 for more information + = help: add `#![feature(coroutines)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks --> $DIR/feature-gate-coroutines.rs:5:5 | @@ -46,7 +86,7 @@ error[E0627]: yield expression outside of coroutine literal LL | yield true; | ^^^^^^^^^^ -error: aborting due to 5 previous errors +error: aborting due to 9 previous errors Some errors have detailed explanations: E0627, E0658. For more information about an error, try `rustc --explain E0627`. diff --git a/tests/ui/feature-gates/feature-gate-coroutines.rs b/tests/ui/feature-gates/feature-gate-coroutines.rs index 28dce8596d396..a686357d910ad 100644 --- a/tests/ui/feature-gates/feature-gate-coroutines.rs +++ b/tests/ui/feature-gates/feature-gate-coroutines.rs @@ -4,17 +4,17 @@ fn main() { yield true; //~ ERROR yield syntax is experimental //~^ ERROR yield expression outside of coroutine literal - //[none]~^^ ERROR yield syntax is experimental + //~^^ ERROR yield syntax is experimental //~^^^ ERROR `yield` can only be used let _ = || yield true; //~ ERROR yield syntax is experimental - //[none]~^ ERROR yield syntax is experimental + //~^ ERROR yield syntax is experimental //~^^ ERROR `yield` can only be used } #[cfg(FALSE)] fn foo() { // Ok in 2024 edition - yield; //[none]~ ERROR yield syntax is experimental - yield 0; //[none]~ ERROR yield syntax is experimental + yield; //~ ERROR yield syntax is experimental + yield 0; //~ ERROR yield syntax is experimental } From 572ae698be3bea00d8ed4ec927c7fa0220f9ceaf Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Mon, 11 Nov 2024 15:50:04 +0100 Subject: [PATCH 16/22] Use completion item indices instead of property matching when searching for the completion item to resolve --- .../rust-analyzer/src/handlers/request.rs | 18 +++++------- .../crates/rust-analyzer/src/lsp/ext.rs | 1 + .../crates/rust-analyzer/src/lsp/to_proto.rs | 29 +++++++++++++++---- 3 files changed, 33 insertions(+), 15 deletions(-) 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 fa584ab4d21b1..a5c9d2823e081 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 @@ -1131,7 +1131,7 @@ pub(crate) fn handle_completion_resolve( else { return Ok(original_completion); }; - let resolved_completions = to_proto::completion_items( + let mut resolved_completions = to_proto::completion_items( &snap.config, &forced_resolve_completions_config.fields_to_resolve, &line_index, @@ -1140,15 +1140,13 @@ pub(crate) fn handle_completion_resolve( resolve_data.trigger_character, resolved_completions, ); - let Some(mut resolved_completion) = resolved_completions.into_iter().find(|completion| { - completion.label == original_completion.label - && completion.kind == original_completion.kind - && completion.deprecated == original_completion.deprecated - && completion.preselect == original_completion.preselect - && completion.sort_text == original_completion.sort_text - }) else { - return Ok(original_completion); - }; + + let mut resolved_completion = + if resolved_completions.get(resolve_data.completion_item_index).is_some() { + resolved_completions.swap_remove(resolve_data.completion_item_index) + } else { + return Ok(original_completion); + }; if !resolve_data.imports.is_empty() { let additional_edits = snap diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs index 8039f0644eecf..6ddfe118d5e6e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs @@ -826,6 +826,7 @@ pub struct CompletionResolveData { pub imports: Vec, pub version: Option, pub trigger_character: Option, + pub completion_item_index: usize, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs index c59e4699f27fd..d444f90a13184 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs @@ -392,18 +392,36 @@ fn completion_item( } else { Vec::new() }; - if something_to_resolve || !imports.is_empty() { - let data = lsp_ext::CompletionResolveData { + let (ref_resolve_data, resolve_data) = if something_to_resolve || !imports.is_empty() { + let mut item_index = acc.len(); + let ref_resolve_data = if ref_match.is_some() { + let ref_resolve_data = lsp_ext::CompletionResolveData { + position: tdpp.clone(), + imports: Vec::new(), + version, + trigger_character: completion_trigger_character, + completion_item_index: item_index, + }; + item_index += 1; + Some(to_value(ref_resolve_data).unwrap()) + } else { + None + }; + let resolve_data = lsp_ext::CompletionResolveData { position: tdpp.clone(), imports, version, trigger_character: completion_trigger_character, + completion_item_index: item_index, }; - lsp_item.data = Some(to_value(data).unwrap()); - } + (ref_resolve_data, Some(to_value(resolve_data).unwrap())) + } else { + (None, None) + }; if let Some((label, indel, relevance)) = ref_match { - let mut lsp_item_with_ref = lsp_types::CompletionItem { label, ..lsp_item.clone() }; + let mut lsp_item_with_ref = + lsp_types::CompletionItem { label, data: ref_resolve_data, ..lsp_item.clone() }; lsp_item_with_ref .additional_text_edits .get_or_insert_with(Default::default) @@ -412,6 +430,7 @@ fn completion_item( acc.push(lsp_item_with_ref); }; + lsp_item.data = resolve_data; acc.push(lsp_item); fn set_score( From e646263abc74ac6b1bba4cb5a1da99e101a59412 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Mon, 11 Nov 2024 16:06:55 +0100 Subject: [PATCH 17/22] Update the file hash --- src/tools/rust-analyzer/docs/dev/lsp-extensions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md index 7764f7843a00b..b7c536e027964 100644 --- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md +++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@ $DIR/hr-associated-type-bound-param-3.rs:18:5 + --> $DIR/hr-associated-type-bound-param-3.rs:18:18 | LL | <(i32,) as X<(i32,)>>::f("abc"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `str` + | ^^^^^^ the trait `Clone` is not implemented for `str` | = help: the trait `Clone` is implemented for `String` note: required by a bound in `X::f` diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-4.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-4.stderr index 6d6373a19182e..da0cf6f55ba7c 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-param-4.stderr +++ b/tests/ui/associated-types/hr-associated-type-bound-param-4.stderr @@ -15,10 +15,10 @@ LL | for<'b> <(T,) as X<'b, T>>::U: Clone, | ^^^^^ required by this bound in `X` error[E0277]: the trait bound `str: Clone` is not satisfied - --> $DIR/hr-associated-type-bound-param-4.rs:18:5 + --> $DIR/hr-associated-type-bound-param-4.rs:18:18 | LL | <(i32,) as X>::f("abc"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `str` + | ^^^ the trait `Clone` is not implemented for `str` | = help: the trait `Clone` is implemented for `String` note: required by a bound in `X::f` diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-5.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-5.stderr index 44c446c599fc7..dd576577dce72 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-param-5.stderr +++ b/tests/ui/associated-types/hr-associated-type-bound-param-5.stderr @@ -31,10 +31,10 @@ LL | for<'b> >::U: Clone, | ^^^^^ required by this bound in `X` error[E0277]: the trait bound `str: Clone` is not satisfied - --> $DIR/hr-associated-type-bound-param-5.rs:36:5 + --> $DIR/hr-associated-type-bound-param-5.rs:36:15 | LL | >>::f("abc"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `str` + | ^^^^^^^^ the trait `Clone` is not implemented for `str` | = help: the trait `Clone` is implemented for `String` note: required by a bound in `X::f` diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-6.rs b/tests/ui/associated-types/hr-associated-type-bound-param-6.rs index f6639904ab33a..c09d3675584e4 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-param-6.rs +++ b/tests/ui/associated-types/hr-associated-type-bound-param-6.rs @@ -17,5 +17,6 @@ impl X<'_, T> for (S,) { pub fn main() { <(i32,) as X>::f("abc"); //~^ ERROR the trait bound `for<'b> i32: X<'b, i32>` is not satisfied + //~| ERROR the trait bound `for<'b> i32: X<'b, i32>` is not satisfied //~| ERROR the trait bound `i32: X<'_, i32>` is not satisfied } diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-6.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-6.stderr index cba83120fdc7d..5278bdb7a5cf2 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-param-6.stderr +++ b/tests/ui/associated-types/hr-associated-type-bound-param-6.stderr @@ -17,6 +17,22 @@ LL | <(i32,) as X>::f("abc"); | = help: the trait `X<'_, T>` is implemented for `(S,)` +error[E0277]: the trait bound `for<'b> i32: X<'b, i32>` is not satisfied + --> $DIR/hr-associated-type-bound-param-6.rs:18:18 + | +LL | <(i32,) as X>::f("abc"); + | ^^^ the trait `for<'b> X<'b, i32>` is not implemented for `i32` + | + = help: the trait `X<'_, T>` is implemented for `(S,)` +note: required by a bound in `X::f` + --> $DIR/hr-associated-type-bound-param-6.rs:3:16 + | +LL | for<'b> T: X<'b, T>, + | ^^^^^^^^ required by this bound in `X::f` +... +LL | fn f(x: &>::U) { + | - required by a bound in this associated function + error[E0277]: the trait bound `i32: X<'_, i32>` is not satisfied --> $DIR/hr-associated-type-bound-param-6.rs:18:27 | @@ -25,6 +41,6 @@ LL | <(i32,) as X>::f("abc"); | = help: the trait `X<'_, T>` is implemented for `(S,)` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr index 3697bd9cf021d..0f5a9de7ab854 100644 --- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `for<'a> T: Trait<'a, '_>` is not satisfied - --> $DIR/candidate-from-env-universe-err-2.rs:15:5 + --> $DIR/candidate-from-env-universe-err-2.rs:15:15 | LL | impl_hr::(); - | ^^^^^^^^^^^^^^ the trait `for<'a> Trait<'a, '_>` is not implemented for `T` + | ^ the trait `for<'a> Trait<'a, '_>` is not implemented for `T` | note: required by a bound in `impl_hr` --> $DIR/candidate-from-env-universe-err-2.rs:12:19 From bea0148ac62758a99dcc2ac2cc2efedacb8881bf Mon Sep 17 00:00:00 2001 From: Boxy Date: Tue, 12 Nov 2024 02:54:03 +0000 Subject: [PATCH 21/22] Consolidate type system const evaluation under `traits::evaluate_const` mew --- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 136 +---------- compiler/rustc_middle/src/mir/consts.rs | 20 +- compiler/rustc_middle/src/ty/consts.rs | 59 +---- compiler/rustc_middle/src/ty/consts/kind.rs | 36 +-- .../src/thir/pattern/const_to_pat.rs | 62 +++-- .../rustc_next_trait_solver/src/delegate.rs | 4 +- .../src/solve/eval_ctxt/mod.rs | 6 +- .../rustc_next_trait_solver/src/solve/mod.rs | 4 +- .../src/solve/normalizes_to/anon_const.rs | 2 +- .../src/solve/delegate.rs | 23 +- .../src/traits/auto_trait.rs | 28 +-- .../src/traits/const_evaluatable.rs | 31 ++- .../src/traits/fulfill.rs | 52 +++-- .../rustc_trait_selection/src/traits/mod.rs | 213 +++++++++++++++++- .../src/traits/normalize.rs | 3 +- .../src/traits/query/normalize.rs | 2 +- .../src/traits/select/confirmation.rs | 2 +- .../src/traits/select/mod.rs | 21 +- .../src/traits/structural_normalize.rs | 2 +- .../clippy_lints/src/large_const_arrays.rs | 2 +- tests/crashes/118545.rs | 8 - tests/crashes/128232.rs | 15 -- .../non_valtreeable_const_arg-1.rs | 12 + .../non_valtreeable_const_arg-1.stderr | 10 + .../non_valtreeable_const_arg-2.rs | 19 ++ .../non_valtreeable_const_arg-2.stderr | 39 ++++ .../unify-op-with-fn-call.rs | 36 --- .../unify-op-with-fn-call.stderr | 93 -------- .../traits/const-traits/const-trait-bounds.rs | 32 --- .../const-traits/const-trait-bounds.stderr | 29 --- 31 files changed, 434 insertions(+), 569 deletions(-) delete mode 100644 tests/crashes/118545.rs delete mode 100644 tests/crashes/128232.rs create mode 100644 tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-1.rs create mode 100644 tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-1.stderr create mode 100644 tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.rs create mode 100644 tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.stderr delete mode 100644 tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs delete mode 100644 tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr delete mode 100644 tests/ui/traits/const-traits/const-trait-bounds.rs delete mode 100644 tests/ui/traits/const-traits/const-trait-bounds.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index ce0ab8a913b0a..c290f96dfdb70 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1491,7 +1491,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } else if self.tcx.features().generic_const_exprs() { - ct.normalize_internal(self.tcx, self.param_env) + rustc_trait_selection::traits::evaluate_const(&self.infcx, ct, self.param_env) } else { ct } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index fc54d69449f04..12df4a10e6364 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -25,10 +25,10 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::extension; pub use rustc_macros::{TypeFoldable, TypeVisitable}; +use rustc_middle::bug; use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey}; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; use rustc_middle::traits::select; pub use rustc_middle::ty::IntVarValue; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -40,7 +40,6 @@ use rustc_middle::ty::{ self, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef, GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid, TypingMode, }; -use rustc_middle::{bug, span_bug}; use rustc_span::Span; use rustc_span::symbol::Symbol; use rustc_type_ir::solve::Reveal; @@ -1279,84 +1278,6 @@ impl<'tcx> InferCtxt<'tcx> { u } - pub fn try_const_eval_resolve( - &self, - param_env: ty::ParamEnv<'tcx>, - unevaluated: ty::UnevaluatedConst<'tcx>, - span: Span, - ) -> Result, ErrorHandled> { - match self.const_eval_resolve(param_env, unevaluated, span) { - Ok(Ok(val)) => Ok(ty::Const::new_value( - self.tcx, - val, - self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args), - )), - Ok(Err(bad_ty)) => { - let tcx = self.tcx; - let def_id = unevaluated.def; - span_bug!( - tcx.def_span(def_id), - "unable to construct a valtree for the unevaluated constant {:?}: type {bad_ty} is not valtree-compatible", - unevaluated - ); - } - Err(err) => Err(err), - } - } - - /// Resolves and evaluates a constant. - /// - /// The constant can be located on a trait like `::C`, in which case the given - /// generic parameters and environment are used to resolve the constant. Alternatively if the - /// constant has generic parameters in scope the instantiations are used to evaluate the value - /// of the constant. For example in `fn foo() { let _ = [0; bar::()]; }` the repeat count - /// constant `bar::()` requires a instantiation for `T`, if the instantiation for `T` is - /// still too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is - /// returned. - /// - /// This handles inferences variables within both `param_env` and `args` by - /// performing the operation on their respective canonical forms. - #[instrument(skip(self), level = "debug")] - pub fn const_eval_resolve( - &self, - mut param_env: ty::ParamEnv<'tcx>, - unevaluated: ty::UnevaluatedConst<'tcx>, - span: Span, - ) -> EvalToValTreeResult<'tcx> { - let mut args = self.resolve_vars_if_possible(unevaluated.args); - debug!(?args); - - // Postpone the evaluation of constants whose args depend on inference - // variables - let tcx = self.tcx; - if args.has_non_region_infer() { - if let Some(ct) = tcx.thir_abstract_const(unevaluated.def)? { - let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, args)); - if let Err(e) = ct.error_reported() { - return Err(ErrorHandled::Reported(e.into(), span)); - } else if ct.has_non_region_infer() || ct.has_non_region_param() { - return Err(ErrorHandled::TooGeneric(span)); - } else { - args = replace_param_and_infer_args_with_placeholder(tcx, args); - } - } else { - args = GenericArgs::identity_for_item(tcx, unevaluated.def); - param_env = tcx.param_env(unevaluated.def); - } - } - - let param_env_erased = tcx.erase_regions(param_env); - let args_erased = tcx.erase_regions(args); - debug!(?param_env_erased); - debug!(?args_erased); - - let unevaluated = ty::UnevaluatedConst { def: unevaluated.def, args: args_erased }; - - // The return value is the evaluated value which doesn't contain any reference to inference - // variables, thus we don't need to instantiate back the original values. - tcx.const_eval_resolve_for_typeck(param_env_erased, unevaluated, span) - } - /// The returned function is used in a fast path. If it returns `true` the variable is /// unchanged, `false` indicates that the status is unknown. #[inline] @@ -1622,61 +1543,6 @@ impl RegionVariableOrigin { } } -/// Replaces args that reference param or infer variables with suitable -/// placeholders. This function is meant to remove these param and infer -/// args when they're not actually needed to evaluate a constant. -fn replace_param_and_infer_args_with_placeholder<'tcx>( - tcx: TyCtxt<'tcx>, - args: GenericArgsRef<'tcx>, -) -> GenericArgsRef<'tcx> { - struct ReplaceParamAndInferWithPlaceholder<'tcx> { - tcx: TyCtxt<'tcx>, - idx: u32, - } - - impl<'tcx> TypeFolder> for ReplaceParamAndInferWithPlaceholder<'tcx> { - fn cx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Infer(_) = t.kind() { - let idx = { - let idx = self.idx; - self.idx += 1; - idx - }; - Ty::new_placeholder(self.tcx, ty::PlaceholderType { - universe: ty::UniverseIndex::ROOT, - bound: ty::BoundTy { - var: ty::BoundVar::from_u32(idx), - kind: ty::BoundTyKind::Anon, - }, - }) - } else { - t.super_fold_with(self) - } - } - - fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { - if let ty::ConstKind::Infer(_) = c.kind() { - ty::Const::new_placeholder(self.tcx, ty::PlaceholderConst { - universe: ty::UniverseIndex::ROOT, - bound: ty::BoundVar::from_u32({ - let idx = self.idx; - self.idx += 1; - idx - }), - }) - } else { - c.super_fold_with(self) - } - } - } - - args.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: 0 }) -} - impl<'tcx> InferCtxt<'tcx> { /// Given a [`hir::Block`], get the span of its last expression or /// statement, peeling off any inner blocks. diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 1ae0bd6740dc9..757034fe30a5e 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -1,17 +1,17 @@ use std::fmt::{self, Debug, Display, Formatter}; -use either::Either; use rustc_abi::{HasDataLayout, Size}; use rustc_hir::def_id::DefId; use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_session::RemapFileNameExt; use rustc_session::config::RemapPathScopeComponents; use rustc_span::{DUMMY_SP, Span}; +use rustc_type_ir::visit::TypeVisitableExt; use crate::mir::interpret::{AllocId, ConstAllocation, ErrorHandled, Scalar, alloc_range}; use crate::mir::{Promoted, pretty_print_const_value}; use crate::ty::print::{pretty_print_const, with_no_trimmed_paths}; -use crate::ty::{self, GenericArgsRef, ScalarInt, Ty, TyCtxt}; +use crate::ty::{self, ConstKind, GenericArgsRef, ScalarInt, Ty, TyCtxt}; /////////////////////////////////////////////////////////////////////////// /// Evaluated Constants @@ -319,15 +319,13 @@ impl<'tcx> Const<'tcx> { ) -> Result, ErrorHandled> { match self { Const::Ty(_, c) => { - // We want to consistently have a "clean" value for type system constants (i.e., no - // data hidden in the padding), so we always go through a valtree here. - match c.eval_valtree(tcx, param_env, span) { - Ok((ty, val)) => Ok(tcx.valtree_to_const_val((ty, val))), - Err(Either::Left(_bad_ty)) => Err(tcx - .dcx() - .delayed_bug("`mir::Const::eval` called on a non-valtree-compatible type") - .into()), - Err(Either::Right(e)) => Err(e), + if c.has_non_region_param() { + return Err(ErrorHandled::TooGeneric(span)); + } + + match c.kind() { + ConstKind::Value(ty, val) => Ok(tcx.valtree_to_const_val((ty, val))), + _ => Err(tcx.dcx().delayed_bug("Unevaluated `ty::Const` in MIR body").into()), } } Const::Unevaluated(uneval, _) => { diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 5ab85a69ce608..5689f3d426541 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -1,4 +1,3 @@ -use either::Either; use rustc_data_structures::intern::Interned; use rustc_error_messages::MultiSpan; use rustc_hir::def::{DefKind, Res}; @@ -9,7 +8,7 @@ use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo}; use tracing::{debug, instrument}; use crate::middle::resolve_bound_vars as rbv; -use crate::mir::interpret::{ErrorHandled, LitToConstInput, Scalar}; +use crate::mir::interpret::{LitToConstInput, Scalar}; use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; mod int; @@ -18,7 +17,7 @@ mod valtree; pub use int::*; pub use kind::*; -use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; +use rustc_span::{DUMMY_SP, ErrorGuaranteed}; pub use valtree::*; pub type ConstKind<'tcx> = ir::ConstKind>; @@ -363,60 +362,6 @@ impl<'tcx> Const<'tcx> { Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize)) } - /// Returns the evaluated constant as a valtree; - /// if that fails due to a valtree-incompatible type, indicate which type that is - /// by returning `Err(Left(bad_type))`. - #[inline] - pub fn eval_valtree( - self, - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - span: Span, - ) -> Result<(Ty<'tcx>, ValTree<'tcx>), Either, ErrorHandled>> { - assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}"); - match self.kind() { - ConstKind::Unevaluated(unevaluated) => { - // FIXME(eddyb) maybe the `const_eval_*` methods should take - // `ty::ParamEnvAnd` instead of having them separate. - let (param_env, unevaluated) = unevaluated.prepare_for_eval(tcx, param_env); - // try to resolve e.g. associated constants to their definition on an impl, and then - // evaluate the const. - match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span) { - Ok(Ok(c)) => { - Ok((tcx.type_of(unevaluated.def).instantiate(tcx, unevaluated.args), c)) - } - Ok(Err(bad_ty)) => Err(Either::Left(bad_ty)), - Err(err) => Err(Either::Right(err)), - } - } - ConstKind::Value(ty, val) => Ok((ty, val)), - ConstKind::Error(g) => Err(Either::Right(g.into())), - ConstKind::Param(_) - | ConstKind::Infer(_) - | ConstKind::Bound(_, _) - | ConstKind::Placeholder(_) - | ConstKind::Expr(_) => Err(Either::Right(ErrorHandled::TooGeneric(span))), - } - } - - /// Normalizes the constant to a value or an error if possible. - #[inline] - pub fn normalize_internal(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self { - match self.eval_valtree(tcx, param_env, DUMMY_SP) { - Ok((ty, val)) => Self::new_value(tcx, val, ty), - Err(Either::Left(_bad_ty)) => { - // This can happen when we run on ill-typed code. - Self::new_error( - tcx, - tcx.dcx() - .delayed_bug("`ty::Const::eval` called on a non-valtree-compatible type"), - ) - } - Err(Either::Right(ErrorHandled::Reported(r, _span))) => Self::new_error(tcx, r.into()), - Err(Either::Right(ErrorHandled::TooGeneric(_span))) => self, - } - } - /// Panics if self.kind != ty::ConstKind::Value pub fn to_valtree(self) -> (ty::ValTree<'tcx>, Ty<'tcx>) { match self.kind() { diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 91b764ae1d451..b3436550e8e07 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -1,46 +1,12 @@ use std::assert_matches::assert_matches; -use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, extension}; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use super::Const; use crate::mir; use crate::ty::abstract_const::CastKind; -use crate::ty::visit::TypeVisitableExt as _; use crate::ty::{self, Ty, TyCtxt}; -#[extension(pub(crate) trait UnevaluatedConstEvalExt<'tcx>)] -impl<'tcx> ty::UnevaluatedConst<'tcx> { - /// FIXME(RalfJung): I cannot explain what this does or why it makes sense, but not doing this - /// hurts performance. - #[inline] - fn prepare_for_eval( - self, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> (ty::ParamEnv<'tcx>, Self) { - // HACK(eddyb) this erases lifetimes even though `const_eval_resolve` - // also does later, but we want to do it before checking for - // inference variables. - // Note that we erase regions *before* calling `with_reveal_all_normalized`, - // so that we don't try to invoke this query with - // any region variables. - - // HACK(eddyb) when the query key would contain inference variables, - // attempt using identity args and `ParamEnv` instead, that will succeed - // when the expression doesn't depend on any parameters. - // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that - // we can call `infcx.const_eval_resolve` which handles inference variables. - if (param_env, self).has_non_region_infer() { - (tcx.param_env(self.def), ty::UnevaluatedConst { - def: self.def, - args: ty::GenericArgs::identity_for_item(tcx, self.def), - }) - } else { - (tcx.erase_regions(param_env).with_reveal_all_normalized(tcx), tcx.erase_regions(self)) - } - } -} - #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] #[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)] pub enum ExprKind { 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 983853d2de186..82632350af59c 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 @@ -1,14 +1,13 @@ -use either::Either; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_apfloat::Float; use rustc_hir as hir; use rustc_index::Idx; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::Obligation; -use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::thir::{FieldPat, Pat, PatKind}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, ValTree}; +use rustc_middle::{mir, span_bug}; use rustc_span::Span; use rustc_trait_selection::traits::ObligationCause; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; @@ -40,7 +39,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // of opaques defined in this function here. let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let mut convert = ConstToPat::new(self, id, span, infcx); - convert.to_pat(c, ty) + + match c.kind() { + ty::ConstKind::Unevaluated(uv) => convert.unevaluated_to_pat(uv, ty), + ty::ConstKind::Value(_, val) => convert.valtree_to_pat(val, ty), + _ => span_bug!(span, "Invalid `ConstKind` for `const_to_pat`: {:?}", c), + } } } @@ -81,27 +85,42 @@ impl<'tcx> ConstToPat<'tcx> { ty.is_structural_eq_shallow(self.infcx.tcx) } - fn to_pat(&mut self, c: ty::Const<'tcx>, ty: Ty<'tcx>) -> Box> { + fn unevaluated_to_pat( + &mut self, + uv: ty::UnevaluatedConst<'tcx>, + ty: Ty<'tcx>, + ) -> Box> { trace!(self.treat_byte_string_as_slice); let pat_from_kind = |kind| Box::new(Pat { span: self.span, ty, kind }); - // Get a valtree. If that fails, this const is definitely not valid for use as a pattern. - let valtree = match c.eval_valtree(self.tcx(), self.param_env, self.span) { - Ok((_, valtree)) => valtree, - Err(Either::Right(e)) => { - let err = match e { - ErrorHandled::Reported(..) => { - // Let's tell the use where this failing const occurs. - self.tcx().dcx().emit_err(CouldNotEvalConstPattern { span: self.span }) - } - ErrorHandled::TooGeneric(_) => self - .tcx() - .dcx() - .emit_err(ConstPatternDependsOnGenericParameter { span: self.span }), - }; - return pat_from_kind(PatKind::Error(err)); + // It's not *technically* correct to be revealing opaque types here as borrowcheck has + // not run yet. However, CTFE itself uses `Reveal::All` unconditionally even during + // typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821). As a + // result we always use a revealed env when resolving the instance to evaluate. + // + // FIXME: `const_eval_resolve_for_typeck` should probably just set the env to `Reveal::All` + // instead of having this logic here + let param_env = + self.tcx().erase_regions(self.param_env).with_reveal_all_normalized(self.tcx()); + let uv = self.tcx().erase_regions(uv); + + // try to resolve e.g. associated constants to their definition on an impl, and then + // evaluate the const. + let valtree = match self.infcx.tcx.const_eval_resolve_for_typeck(param_env, uv, self.span) { + Ok(Ok(c)) => c, + Err(ErrorHandled::Reported(_, _)) => { + // Let's tell the use where this failing const occurs. + let e = self.tcx().dcx().emit_err(CouldNotEvalConstPattern { span: self.span }); + return pat_from_kind(PatKind::Error(e)); } - Err(Either::Left(bad_ty)) => { + Err(ErrorHandled::TooGeneric(_)) => { + let e = self + .tcx() + .dcx() + .emit_err(ConstPatternDependsOnGenericParameter { span: self.span }); + return pat_from_kind(PatKind::Error(e)); + } + Ok(Err(bad_ty)) => { // The pattern cannot be turned into a valtree. let e = match bad_ty.kind() { ty::Adt(def, ..) => { @@ -128,8 +147,7 @@ impl<'tcx> ConstToPat<'tcx> { if !self.type_has_partial_eq_impl(ty) { let err = TypeNotPartialEq { span: self.span, non_peq_ty: ty }; let e = self.tcx().dcx().emit_err(err); - let kind = PatKind::Error(e); - return Box::new(Pat { span: self.span, ty, kind }); + return pat_from_kind(PatKind::Error(e)); } } diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index f7fbfed5b8e38..4ba54a2e0bf23 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -29,10 +29,10 @@ pub trait SolverDelegate: Deref::Infcx> + Size // FIXME: Uplift the leak check into this crate. fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution>; - fn try_const_eval_resolve( + fn evaluate_const( &self, param_env: ::ParamEnv, - unevaluated: ty::UnevaluatedConst, + uv: ty::UnevaluatedConst, ) -> Option<::Const>; // FIXME: This only is here because `wf::obligations` is in `rustc_trait_selection`! diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 8685896715e1e..979a379474822 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1001,12 +1001,12 @@ where // Try to evaluate a const, or return `None` if the const is too generic. // This doesn't mean the const isn't evaluatable, though, and should be treated // as an ambiguity rather than no-solution. - pub(super) fn try_const_eval_resolve( + pub(super) fn evaluate_const( &self, param_env: I::ParamEnv, - unevaluated: ty::UnevaluatedConst, + uv: ty::UnevaluatedConst, ) -> Option { - self.delegate.try_const_eval_resolve(param_env, unevaluated) + self.delegate.evaluate_const(param_env, uv) } pub(super) fn is_transmutable( diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 6793779b205d1..5c54656cc59f5 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -143,7 +143,7 @@ where ) -> QueryResult { match ct.kind() { ty::ConstKind::Unevaluated(uv) => { - // We never return `NoSolution` here as `try_const_eval_resolve` emits an + // We never return `NoSolution` here as `evaluate_const` emits an // error itself when failing to evaluate, so emitting an additional fulfillment // error in that case is unnecessary noise. This may change in the future once // evaluation failures are allowed to impact selection, e.g. generic const @@ -151,7 +151,7 @@ where // FIXME(generic_const_exprs): Implement handling for generic // const expressions here. - if let Some(_normalized) = self.try_const_eval_resolve(param_env, uv) { + if let Some(_normalized) = self.evaluate_const(param_env, uv) { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs index 5d5597429da45..8ad0bf5cdf9a4 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs @@ -14,7 +14,7 @@ where &mut self, goal: Goal>, ) -> QueryResult { - if let Some(normalized_const) = self.try_const_eval_resolve( + if let Some(normalized_const) = self.evaluate_const( goal.param_env, ty::UnevaluatedConst::new(goal.predicate.alias.def_id, goal.predicate.alias.args), ) { diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index c53689b211d2a..2cc787c8bc577 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -15,7 +15,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use rustc_type_ir::TypingMode; use rustc_type_ir::solve::{Certainty, NoSolution}; -use crate::traits::specialization_graph; +use crate::traits::{EvaluateConstErr, specialization_graph}; #[repr(transparent)] pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>); @@ -77,20 +77,19 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution) } - fn try_const_eval_resolve( + fn evaluate_const( &self, param_env: ty::ParamEnv<'tcx>, - unevaluated: ty::UnevaluatedConst<'tcx>, + uv: ty::UnevaluatedConst<'tcx>, ) -> Option> { - use rustc_middle::mir::interpret::ErrorHandled; - match self.const_eval_resolve(param_env, unevaluated, DUMMY_SP) { - Ok(Ok(val)) => Some(ty::Const::new_value( - self.tcx, - val, - self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args), - )), - Ok(Err(_)) | Err(ErrorHandled::TooGeneric(_)) => None, - Err(ErrorHandled::Reported(e, _)) => Some(ty::Const::new_error(self.tcx, e.into())), + let ct = ty::Const::new_unevaluated(self.tcx, uv); + + match crate::traits::try_evaluate_const(&self.0, ct, param_env) { + Ok(ct) => Some(ct), + Err(EvaluateConstErr::EvaluationFailure(e)) => Some(ty::Const::new_error(self.tcx, e)), + Err( + EvaluateConstErr::InvalidConstParamTy(_) | EvaluateConstErr::HasGenericsOrInfers, + ) => None, } } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 52ba5621d3191..103f7c76a86d7 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -7,7 +7,6 @@ use std::iter; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry}; use rustc_data_structures::unord::UnordSet; use rustc_infer::infer::DefineOpaqueTypes; -use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::{Region, RegionVid}; use tracing::debug; use ty::TypingMode; @@ -761,23 +760,20 @@ impl<'tcx> AutoTraitFinder<'tcx> { ty::PredicateKind::ConstEquate(c1, c2) => { let evaluate = |c: ty::Const<'tcx>| { if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() { - match selcx.infcx.const_eval_resolve( + let ct = super::try_evaluate_const( + selcx.infcx, + c, obligation.param_env, - unevaluated, - obligation.cause.span, - ) { - Ok(Ok(valtree)) => Ok(ty::Const::new_value(selcx.tcx(),valtree, self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args))), - Ok(Err(_)) => { - let tcx = self.tcx; - let reported = - tcx.dcx().emit_err(UnableToConstructConstantValue { - span: tcx.def_span(unevaluated.def), - unevaluated, - }); - Err(ErrorHandled::Reported(reported.into(), tcx.def_span(unevaluated.def))) - } - Err(err) => Err(err), + ); + + if let Err(EvaluateConstErr::InvalidConstParamTy(_)) = ct { + self.tcx.dcx().emit_err(UnableToConstructConstantValue { + span: self.tcx.def_span(unevaluated.def), + unevaluated, + }); } + + ct } else { Ok(c) } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 1be3c96445465..15eb5d74cbfa5 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -12,13 +12,13 @@ use rustc_hir::def::DefKind; use rustc_infer::infer::InferCtxt; use rustc_middle::bug; -use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::{self, TyCtxt, TypeVisitable, TypeVisitableExt, TypeVisitor}; use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument}; +use super::EvaluateConstErr; use crate::traits::ObligationCtxt; /// Check if a given constant can be evaluated. @@ -68,16 +68,18 @@ pub fn is_const_evaluatable<'tcx>( // here. tcx.dcx().span_bug(span, "evaluating `ConstKind::Expr` is not currently supported"); } - ty::ConstKind::Unevaluated(uv) => { - let concrete = infcx.const_eval_resolve(param_env, uv, span); - match concrete { - Err(ErrorHandled::TooGeneric(_)) => { + ty::ConstKind::Unevaluated(_) => { + match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env) { + Err(EvaluateConstErr::HasGenericsOrInfers) => { Err(NotConstEvaluatable::Error(infcx.dcx().span_delayed_bug( span, "Missing value for constant, but no error reported?", ))) } - Err(ErrorHandled::Reported(e, _)) => Err(NotConstEvaluatable::Error(e.into())), + Err( + EvaluateConstErr::EvaluationFailure(e) + | EvaluateConstErr::InvalidConstParamTy(e), + ) => Err(NotConstEvaluatable::Error(e.into())), Ok(_) => Ok(()), } } @@ -92,16 +94,7 @@ pub fn is_const_evaluatable<'tcx>( _ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"), }; - // FIXME: We should only try to evaluate a given constant here if it is fully concrete - // as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`. - // - // We previously did not check this, so we only emit a future compat warning if - // const evaluation succeeds and the given constant is still polymorphic for now - // and hopefully soon change this to an error. - // - // See #74595 for more details about this. - let concrete = infcx.const_eval_resolve(param_env, uv, span); - match concrete { + match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env) { // If we're evaluating a generic foreign constant, under a nightly compiler while // the current crate does not enable `feature(generic_const_exprs)`, abort // compilation with a useful error. @@ -130,7 +123,7 @@ pub fn is_const_evaluatable<'tcx>( .emit() } - Err(ErrorHandled::TooGeneric(_)) => { + Err(EvaluateConstErr::HasGenericsOrInfers) => { let err = if uv.has_non_region_infer() { NotConstEvaluatable::MentionsInfer } else if uv.has_non_region_param() { @@ -145,7 +138,9 @@ pub fn is_const_evaluatable<'tcx>( Err(err) } - Err(ErrorHandled::Reported(e, _)) => Err(NotConstEvaluatable::Error(e.into())), + Err( + EvaluateConstErr::EvaluationFailure(e) | EvaluateConstErr::InvalidConstParamTy(e), + ) => Err(NotConstEvaluatable::Error(e.into())), Ok(_) => Ok(()), } } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 21141f6e18f39..2ec5f0d22496d 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -10,7 +10,6 @@ use rustc_infer::traits::{ TraitEngine, }; use rustc_middle::bug; -use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode}; @@ -26,6 +25,7 @@ use super::{ }; use crate::error_reporting::InferCtxtErrorExt; use crate::infer::{InferCtxt, TyOrConstInferVar}; +use crate::traits::EvaluateConstErr; use crate::traits::normalize::normalize_with_depth_to; use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _}; use crate::traits::query::evaluate_obligation::InferCtxtExt; @@ -664,23 +664,25 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { let mut evaluate = |c: Const<'tcx>| { if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() { - match self.selcx.infcx.try_const_eval_resolve( + match super::try_evaluate_const( + self.selcx.infcx, + c, obligation.param_env, - unevaluated, - obligation.cause.span, ) { Ok(val) => Ok(val), - Err(e) => { - match e { - ErrorHandled::TooGeneric(..) => { - stalled_on.extend(unevaluated.args.iter().filter_map( - TyOrConstInferVar::maybe_from_generic_arg, - )); - } - _ => {} - } - Err(e) + e @ Err(EvaluateConstErr::HasGenericsOrInfers) => { + stalled_on.extend( + unevaluated + .args + .iter() + .filter_map(TyOrConstInferVar::maybe_from_generic_arg), + ); + e } + e @ Err( + EvaluateConstErr::EvaluationFailure(_) + | EvaluateConstErr::InvalidConstParamTy(_), + ) => e, } } else { Ok(c) @@ -707,14 +709,20 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } } - (Err(ErrorHandled::Reported(reported, _)), _) - | (_, Err(ErrorHandled::Reported(reported, _))) => ProcessResult::Error( - FulfillmentErrorCode::Select(SelectionError::NotConstEvaluatable( - NotConstEvaluatable::Error(reported.into()), - )), - ), - (Err(ErrorHandled::TooGeneric(_)), _) - | (_, Err(ErrorHandled::TooGeneric(_))) => { + (Err(EvaluateConstErr::InvalidConstParamTy(e)), _) + | (_, Err(EvaluateConstErr::InvalidConstParamTy(e))) => { + ProcessResult::Error(FulfillmentErrorCode::Select( + SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(e)), + )) + } + (Err(EvaluateConstErr::EvaluationFailure(e)), _) + | (_, Err(EvaluateConstErr::EvaluationFailure(e))) => { + ProcessResult::Error(FulfillmentErrorCode::Select( + SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(e)), + )) + } + (Err(EvaluateConstErr::HasGenericsOrInfers), _) + | (_, Err(EvaluateConstErr::HasGenericsOrInfers)) => { if c1.has_non_region_infer() || c2.has_non_region_infer() { ProcessResult::Unchanged } else { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 436c0fabd2966..17636d432aeed 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -27,6 +27,7 @@ use std::fmt::Debug; use std::ops::ControlFlow; use rustc_errors::ErrorGuaranteed; +use rustc_hir::def::DefKind; pub use rustc_infer::traits::*; use rustc_middle::query::Providers; use rustc_middle::span_bug; @@ -34,11 +35,11 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{ - self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, TypingMode, - Upcast, + self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, + TypeSuperVisitable, TypingMode, Upcast, }; -use rustc_span::Span; use rustc_span::def_id::DefId; +use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument}; pub use self::coherence::{ @@ -366,11 +367,23 @@ pub fn normalize_param_env_or_error<'tcx>( if c.has_escaping_bound_vars() { return ty::Const::new_misc_error(self.0); } + // While it is pretty sus to be evaluating things with an empty param env, it // should actually be okay since without `feature(generic_const_exprs)` the only // const arguments that have a non-empty param env are array repeat counts. These // do not appear in the type system though. - c.normalize_internal(self.0, ty::ParamEnv::empty()) + if let ty::ConstKind::Unevaluated(uv) = c.kind() + && self.0.def_kind(uv.def) == DefKind::AnonConst + { + let infcx = self.0.infer_ctxt().build(TypingMode::non_body_analysis()); + let c = evaluate_const(&infcx, c, ty::ParamEnv::empty()); + // We should never wind up with any `infcx` local state when normalizing anon consts + // under min const generics. + assert!(!c.has_infer() && !c.has_placeholders()); + return c; + } + + c } } @@ -474,6 +487,198 @@ pub fn normalize_param_env_or_error<'tcx>( ty::ParamEnv::new(tcx.mk_clauses(&predicates), unnormalized_env.reveal()) } +#[derive(Debug)] +pub enum EvaluateConstErr { + /// The constant being evaluated was either a generic parameter or inference variable, *or*, + /// some unevaluated constant with either generic parameters or inference variables in its + /// generic arguments. + HasGenericsOrInfers, + /// The type this constant evalauted to is not valid for use in const generics. This should + /// always result in an error when checking the constant is correctly typed for the parameter + /// it is an argument to, so a bug is delayed when encountering this. + InvalidConstParamTy(ErrorGuaranteed), + /// CTFE failed to evaluate the constant in some unrecoverable way (e.g. encountered a `panic!`). + /// This is also used when the constant was already tainted by error. + EvaluationFailure(ErrorGuaranteed), +} + +// FIXME(BoxyUwU): Private this once we `generic_const_exprs` isn't doing its own normalization routine +// FIXME(generic_const_exprs): Consider accepting a `ty::UnevaluatedConst` when we are not rolling our own +// normalization scheme +/// Evaluates a type system constant returning a `ConstKind::Error` in cases where CTFE failed and +/// returning the passed in constant if it was not fully concrete (i.e. depended on generic parameters +/// or inference variables) +/// +/// You should not call this function unless you are implementing normalization itself. Prefer to use +/// `normalize_erasing_regions` or the `normalize` functions on `ObligationCtxt`/`FnCtxt`/`InferCtxt`. +pub fn evaluate_const<'tcx>( + infcx: &InferCtxt<'tcx>, + ct: ty::Const<'tcx>, + param_env: ty::ParamEnv<'tcx>, +) -> ty::Const<'tcx> { + match try_evaluate_const(infcx, ct, param_env) { + Ok(ct) => ct, + Err(EvaluateConstErr::EvaluationFailure(e) | EvaluateConstErr::InvalidConstParamTy(e)) => { + ty::Const::new_error(infcx.tcx, e) + } + Err(EvaluateConstErr::HasGenericsOrInfers) => ct, + } +} + +// FIXME(BoxyUwU): Private this once we `generic_const_exprs` isn't doing its own normalization routine +// FIXME(generic_const_exprs): Consider accepting a `ty::UnevaluatedConst` when we are not rolling our own +// normalization scheme +/// Evaluates a type system constant making sure to not allow constants that depend on generic parameters +/// or inference variables to succeed in evaluating. +/// +/// You should not call this function unless you are implementing normalization itself. Prefer to use +/// `normalize_erasing_regions` or the `normalize` functions on `ObligationCtxt`/`FnCtxt`/`InferCtxt`. +#[instrument(level = "debug", skip(infcx), ret)] +pub fn try_evaluate_const<'tcx>( + infcx: &InferCtxt<'tcx>, + ct: ty::Const<'tcx>, + param_env: ty::ParamEnv<'tcx>, +) -> Result, EvaluateConstErr> { + let tcx = infcx.tcx; + let ct = infcx.resolve_vars_if_possible(ct); + debug!(?ct); + + match ct.kind() { + ty::ConstKind::Value(..) => Ok(ct), + ty::ConstKind::Error(e) => Err(EvaluateConstErr::EvaluationFailure(e)), + ty::ConstKind::Param(_) + | ty::ConstKind::Infer(_) + | ty::ConstKind::Bound(_, _) + | ty::ConstKind::Placeholder(_) + | ty::ConstKind::Expr(_) => Err(EvaluateConstErr::HasGenericsOrInfers), + ty::ConstKind::Unevaluated(uv) => { + // Postpone evaluation of constants that depend on generic parameters or inference variables. + let (args, param_env) = if tcx.features().generic_const_exprs() + && uv.has_non_region_infer() + { + // `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause + // inference variables and generic parameters to show up in `ty::Const` even though the anon const + // does not actually make use of them. We handle this case specially and attempt to evaluate anyway. + match tcx.thir_abstract_const(uv.def) { + Ok(Some(ct)) => { + let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args)); + if let Err(e) = ct.error_reported() { + return Err(EvaluateConstErr::EvaluationFailure(e)); + } else if ct.has_non_region_infer() || ct.has_non_region_param() { + // If the anon const *does* actually use generic parameters or inference variables from + // the generic arguments provided for it, then we should *not* attempt to evaluate it. + return Err(EvaluateConstErr::HasGenericsOrInfers); + } else { + (replace_param_and_infer_args_with_placeholder(tcx, uv.args), param_env) + } + } + Err(_) | Ok(None) => { + let args = GenericArgs::identity_for_item(tcx, uv.def); + let param_env = tcx.param_env(uv.def); + (args, param_env) + } + } + } else { + // FIXME: We don't check anything on stable as the only way we can wind up with + // an unevaluated constant containing generic parameters is through array repeat + // expression counts which have a future compat lint for usage of generic parameters + // instead of a hard error. + // + // This codepath is however also reachable by `generic_const_exprs` and some other + // feature gates which allow constants in the type system to use generic parameters. + // In theory we should be checking for generic parameters here and returning an error + // in such cases. + (uv.args, param_env) + }; + let uv = ty::UnevaluatedConst::new(uv.def, args); + + // It's not *technically* correct to be revealing opaque types here as we could still be + // before borrowchecking. However, CTFE itself uses `Reveal::All` unconditionally even during + // typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821). As a result we + // always use a revealed env when resolving the instance to evaluate. + // + // FIXME: `const_eval_resolve_for_typeck` should probably just set the env to `Reveal::All` + // instead of having this logic here + let env = tcx.erase_regions(param_env).with_reveal_all_normalized(tcx); + let erased_uv = tcx.erase_regions(uv); + + use rustc_middle::mir::interpret::ErrorHandled; + match tcx.const_eval_resolve_for_typeck(env, erased_uv, DUMMY_SP) { + Ok(Ok(val)) => Ok(ty::Const::new_value( + tcx, + val, + tcx.type_of(uv.def).instantiate(tcx, uv.args), + )), + Ok(Err(_)) => { + let e = tcx.dcx().delayed_bug( + "Type system constant with non valtree'able type evaluated but no error emitted", + ); + Err(EvaluateConstErr::InvalidConstParamTy(e)) + } + Err(ErrorHandled::Reported(info, _)) => { + Err(EvaluateConstErr::EvaluationFailure(info.into())) + } + Err(ErrorHandled::TooGeneric(_)) => Err(EvaluateConstErr::HasGenericsOrInfers), + } + } + } +} + +/// Replaces args that reference param or infer variables with suitable +/// placeholders. This function is meant to remove these param and infer +/// args when they're not actually needed to evaluate a constant. +fn replace_param_and_infer_args_with_placeholder<'tcx>( + tcx: TyCtxt<'tcx>, + args: GenericArgsRef<'tcx>, +) -> GenericArgsRef<'tcx> { + struct ReplaceParamAndInferWithPlaceholder<'tcx> { + tcx: TyCtxt<'tcx>, + idx: u32, + } + + impl<'tcx> TypeFolder> for ReplaceParamAndInferWithPlaceholder<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if let ty::Infer(_) = t.kind() { + let idx = { + let idx = self.idx; + self.idx += 1; + idx + }; + Ty::new_placeholder(self.tcx, ty::PlaceholderType { + universe: ty::UniverseIndex::ROOT, + bound: ty::BoundTy { + var: ty::BoundVar::from_u32(idx), + kind: ty::BoundTyKind::Anon, + }, + }) + } else { + t.super_fold_with(self) + } + } + + fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { + if let ty::ConstKind::Infer(_) = c.kind() { + ty::Const::new_placeholder(self.tcx, ty::PlaceholderConst { + universe: ty::UniverseIndex::ROOT, + bound: ty::BoundVar::from_u32({ + let idx = self.idx; + self.idx += 1; + idx + }), + }) + } else { + c.super_fold_with(self) + } + } + } + + args.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: 0 }) +} + /// Normalizes the predicates and checks whether they hold in an empty environment. If this /// returns true, then either normalize encountered an error or one of the predicates did not /// hold. Used when creating vtables to check for unsatisfiable methods. This should not be diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 954dfe93387de..5c38d162712e6 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -418,8 +418,9 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx self.selcx.infcx, &mut self.universes, constant, - |constant| constant.normalize_internal(tcx, self.param_env), + |constant| super::evaluate_const(self.selcx.infcx, constant, self.param_env), ) + .super_fold_with(self) } } diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index a8d701a750dd0..5f89894fb82ed 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -342,7 +342,7 @@ impl<'a, 'tcx> FallibleTypeFolder> for QueryNormalizer<'a, 'tcx> { self.infcx, &mut self.universes, constant, - |constant| constant.normalize_internal(self.infcx.tcx, self.param_env), + |constant| crate::traits::evaluate_const(&self.infcx, constant, self.param_env), ); debug!(?constant, ?self.param_env); constant.try_super_fold_with(self) diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 041cfc212670e..712856e6a8f2d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -403,7 +403,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut assume = predicate.trait_ref.args.const_at(2); // FIXME(min_generic_const_exprs): We should shallowly normalize this. if self.tcx().features().generic_const_exprs() { - assume = assume.normalize_internal(self.tcx(), obligation.param_env); + assume = crate::traits::evaluate_const(self.infcx, assume, obligation.param_env) } let Some(assume) = rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index cffb62ab559ba..5b4e895189b0e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -22,7 +22,6 @@ use rustc_infer::infer::relate::TypeRelation; use rustc_infer::traits::{PredicateObligations, TraitObligation}; use rustc_middle::bug; use rustc_middle::dep_graph::{DepNodeIndex, dep_kinds}; -use rustc_middle::mir::interpret::ErrorHandled; pub use rustc_middle::traits::select::*; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::TypeErrorToStringExt; @@ -50,7 +49,7 @@ use crate::infer::{InferCtxt, InferOk, TypeFreshener}; use crate::solve::InferCtxtSelectExt as _; use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt}; -use crate::traits::{ProjectionCacheKey, Unimplemented, effects}; +use crate::traits::{EvaluateConstErr, ProjectionCacheKey, Unimplemented, effects}; mod _match; mod candidate_assembly; @@ -931,11 +930,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } let evaluate = |c: ty::Const<'tcx>| { - if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() { - match self.infcx.try_const_eval_resolve( + if let ty::ConstKind::Unevaluated(_) = c.kind() { + match crate::traits::try_evaluate_const( + self.infcx, + c, obligation.param_env, - unevaluated, - obligation.cause.span, ) { Ok(val) => Ok(val), Err(e) => Err(e), @@ -961,10 +960,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Err(_) => Ok(EvaluatedToErr), } } - (Err(ErrorHandled::Reported(..)), _) - | (_, Err(ErrorHandled::Reported(..))) => Ok(EvaluatedToErr), - (Err(ErrorHandled::TooGeneric(..)), _) - | (_, Err(ErrorHandled::TooGeneric(..))) => { + (Err(EvaluateConstErr::InvalidConstParamTy(..)), _) + | (_, Err(EvaluateConstErr::InvalidConstParamTy(..))) => Ok(EvaluatedToErr), + (Err(EvaluateConstErr::EvaluationFailure(..)), _) + | (_, Err(EvaluateConstErr::EvaluationFailure(..))) => Ok(EvaluatedToErr), + (Err(EvaluateConstErr::HasGenericsOrInfers), _) + | (_, Err(EvaluateConstErr::HasGenericsOrInfers)) => { if c1.has_non_region_infer() || c2.has_non_region_infer() { Ok(EvaluatedToAmbig) } else { diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index 23b5f62b5ca49..f8e8f2176c182 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -83,7 +83,7 @@ impl<'tcx> At<'_, 'tcx> { Ok(self.infcx.resolve_vars_if_possible(new_infer_ct)) } else if self.infcx.tcx.features().generic_const_exprs() { - Ok(ct.normalize_internal(self.infcx.tcx, self.param_env)) + Ok(super::evaluate_const(&self.infcx, ct, self.param_env)) } else { Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx)) } diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs index aa8b4d88d2f27..44b9d6adaaab1 100644 --- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs @@ -56,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { && !item.span.from_expansion() && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() && let ty::Array(element_type, cst) = ty.kind() - && let Ok((_, ty::ValTree::Leaf(element_count))) = cst.eval_valtree(cx.tcx, ParamEnv::empty(), item.span) + && let Some((ty::ValTree::Leaf(element_count), _)) = cx.tcx.try_normalize_erasing_regions(ParamEnv::empty(), *cst).unwrap_or(*cst).try_to_valtree() && let element_count = element_count.to_target_usize(cx.tcx) && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) && u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size) diff --git a/tests/crashes/118545.rs b/tests/crashes/118545.rs deleted file mode 100644 index 1d4bb848bf04e..0000000000000 --- a/tests/crashes/118545.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #118545 -#![feature(generic_const_exprs)] - -struct Checked; - -fn foo() {} -const _: Checked = Checked::; -pub fn main() {} diff --git a/tests/crashes/128232.rs b/tests/crashes/128232.rs deleted file mode 100644 index 67f61e1b2402c..0000000000000 --- a/tests/crashes/128232.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ known-bug: #128232 - -#![feature(generic_const_exprs, unsized_const_params)] - -fn function() {} - -struct Wrapper; - -impl Wrapper<{ bar() }> { - fn call() {} -} - -fn main() { - Wrapper::::call; -} diff --git a/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-1.rs b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-1.rs new file mode 100644 index 0000000000000..cea82722a0e60 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-1.rs @@ -0,0 +1,12 @@ +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +// Regression test for #118545 + +struct Checked; +//~^ ERROR: using function pointers as const generic parameters is forbidden + +fn foo() {} +const _: Checked = Checked::; + +pub fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-1.stderr b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-1.stderr new file mode 100644 index 0000000000000..71339411c847e --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-1.stderr @@ -0,0 +1,10 @@ +error: using function pointers as const generic parameters is forbidden + --> $DIR/non_valtreeable_const_arg-1.rs:6:25 + | +LL | struct Checked; + | ^^^^ + | + = note: the only supported types are integers, `bool`, and `char` + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.rs b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.rs new file mode 100644 index 0000000000000..6b87ad86d4bc2 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.rs @@ -0,0 +1,19 @@ +#![feature(generic_const_exprs, unsized_const_params)] +#![allow(incomplete_features)] + +// Regression test for 128232 + +fn function() {} + +struct Wrapper; +//~^ ERROR: using function pointers as const generic parameters is forbidden + +impl Wrapper<{ bar() }> { + //~^ ERROR: cannot find function `bar` in this scope + fn call() {} +} + +fn main() { + Wrapper::::call; + //~^ ERROR: the function or associated item `call` exists for struct `Wrapper`, +} diff --git a/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.stderr b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.stderr new file mode 100644 index 0000000000000..b13f76eabadbc --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.stderr @@ -0,0 +1,39 @@ +error[E0425]: cannot find function `bar` in this scope + --> $DIR/non_valtreeable_const_arg-2.rs:11:16 + | +LL | impl Wrapper<{ bar() }> { + | ^^^ not found in this scope + | +help: you might be missing a const parameter + | +LL | impl Wrapper<{ bar() }> { + | +++++++++++++++++++++++ + +error[E0741]: using function pointers as const generic parameters is forbidden + --> $DIR/non_valtreeable_const_arg-2.rs:8:25 + | +LL | struct Wrapper; + | ^^^^ + +error[E0599]: the function or associated item `call` exists for struct `Wrapper`, but its trait bounds were not satisfied + --> $DIR/non_valtreeable_const_arg-2.rs:17:26 + | +LL | struct Wrapper; + | ----------------------------- function or associated item `call` not found for this struct because it doesn't satisfy `Wrapper: Fn<_>` +... +LL | Wrapper::::call; + | ^^^^ function or associated item cannot be called on `Wrapper` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `Wrapper: Fn<_>` + which is required by `&Wrapper: Fn<_>` +note: the trait `Fn` must be implemented + --> $SRC_DIR/core/src/ops/function.rs:LL:COL + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `call`, perhaps you need to implement it: + candidate #1: `Fn` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0425, E0599, E0741. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs b/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs deleted file mode 100644 index 6c0ac639612cd..0000000000000 --- a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs +++ /dev/null @@ -1,36 +0,0 @@ -//@ known-bug: #110395 -//@ compile-flags: -Znext-solver -#![feature(generic_const_exprs, adt_const_params, const_trait_impl)] -#![allow(incomplete_features)] - -// test `N + N` unifies with explicit function calls for non-builtin-types -#[derive(PartialEq, Eq)] -struct Foo(u8); - -impl const std::ops::Add for Foo { - type Output = Self; - - fn add(self, rhs: Self) -> Self::Output { - self - } -} - -struct Evaluatable; - -fn foo(a: Evaluatable<{ N + N }>) { - bar::<{ std::ops::Add::add(N, N) }>(); -} - -fn bar() {} - -// test that `N + N` unifies with explicit function calls for builin-types -struct Evaluatable2; - -fn foo2(a: Evaluatable2<{ N + N }>) { - bar2::<{ std::ops::Add::add(N, N) }>(); - // FIXME(generic_const_exprs) make this not an error -} - -fn bar2() {} - -fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr b/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr deleted file mode 100644 index 882fdf0b228e8..0000000000000 --- a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr +++ /dev/null @@ -1,93 +0,0 @@ -error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed - --> $DIR/unify-op-with-fn-call.rs:3:12 - | -LL | #![feature(generic_const_exprs, adt_const_params, const_trait_impl)] - | ^^^^^^^^^^^^^^^^^^^ - | - = help: remove one of these features - -error: const `impl` for trait `Add` which is not marked with `#[const_trait]` - --> $DIR/unify-op-with-fn-call.rs:10:12 - | -LL | impl const std::ops::Add for Foo { - | ^^^^^^^^^^^^^ - | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` - = note: adding a non-const method body in the future would be a breaking change - -error[E0741]: `Foo` must implement `ConstParamTy` to be used as the type of a const generic parameter - --> $DIR/unify-op-with-fn-call.rs:18:29 - | -LL | struct Evaluatable; - | ^^^ - | -help: add `#[derive(ConstParamTy)]` to the struct - | -LL + #[derive(ConstParamTy)] -LL | struct Foo(u8); - | - -error[E0015]: cannot call non-const operator in constants - --> $DIR/unify-op-with-fn-call.rs:20:39 - | -LL | fn foo(a: Evaluatable<{ N + N }>) { - | ^^^^^ - | - = note: calls in constants are limited to constant functions, tuple structs and tuple variants - -error[E0741]: `Foo` must implement `ConstParamTy` to be used as the type of a const generic parameter - --> $DIR/unify-op-with-fn-call.rs:20:17 - | -LL | fn foo(a: Evaluatable<{ N + N }>) { - | ^^^ - | -help: add `#[derive(ConstParamTy)]` to the struct - | -LL + #[derive(ConstParamTy)] -LL | struct Foo(u8); - | - -error[E0741]: `Foo` must implement `ConstParamTy` to be used as the type of a const generic parameter - --> $DIR/unify-op-with-fn-call.rs:24:17 - | -LL | fn bar() {} - | ^^^ - | -help: add `#[derive(ConstParamTy)]` to the struct - | -LL + #[derive(ConstParamTy)] -LL | struct Foo(u8); - | - -error[E0284]: type annotations needed: cannot normalize `foo2::{constant#0}` - --> $DIR/unify-op-with-fn-call.rs:29:28 - | -LL | fn foo2(a: Evaluatable2<{ N + N }>) { - | ^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo2::{constant#0}` - -error[E0015]: cannot call non-const fn `::add` in constants - --> $DIR/unify-op-with-fn-call.rs:21:13 - | -LL | bar::<{ std::ops::Add::add(N, N) }>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constants are limited to constant functions, tuple structs and tuple variants - -error[E0015]: cannot call non-const fn `::add` in constants - --> $DIR/unify-op-with-fn-call.rs:30:14 - | -LL | bar2::<{ std::ops::Add::add(N, N) }>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constants are limited to constant functions, tuple structs and tuple variants - -error[E0284]: type annotations needed: cannot normalize `foo2::{constant#0}` - --> $DIR/unify-op-with-fn-call.rs:30:12 - | -LL | bar2::<{ std::ops::Add::add(N, N) }>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo2::{constant#0}` - -error: aborting due to 10 previous errors - -Some errors have detailed explanations: E0015, E0284, E0741. -For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/const-trait-bounds.rs b/tests/ui/traits/const-traits/const-trait-bounds.rs deleted file mode 100644 index 8722d9909edda..0000000000000 --- a/tests/ui/traits/const-traits/const-trait-bounds.rs +++ /dev/null @@ -1,32 +0,0 @@ -//@ known-bug: #110395 -//@ compile-flags: -Znext-solver -// FIXME(const_trait_impl): check-pass -#![feature(const_trait_impl, generic_const_exprs)] -#![allow(incomplete_features)] - -fn main() { - let _ = process::<()>([()]); - let _ = Struct::<(), 4> { field: [1, 0] }; -} - -fn process(input: [(); T::make(2)]) -> [(); T::make(2)] { - input -} - -struct Struct -where - [u32; T::make(P)]:, -{ - field: [u32; T::make(P)], -} - -#[const_trait] -trait Trait { - fn make(input: usize) -> usize; -} - -impl const Trait for () { - fn make(input: usize) -> usize { - input / 2 - } -} diff --git a/tests/ui/traits/const-traits/const-trait-bounds.stderr b/tests/ui/traits/const-traits/const-trait-bounds.stderr deleted file mode 100644 index 29a01b9d7dcef..0000000000000 --- a/tests/ui/traits/const-traits/const-trait-bounds.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed - --> $DIR/const-trait-bounds.rs:4:30 - | -LL | #![feature(const_trait_impl, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = help: remove one of these features - -error[E0284]: type annotations needed: cannot normalize `process::{constant#0}` - --> $DIR/const-trait-bounds.rs:12:35 - | -LL | fn process(input: [(); T::make(2)]) -> [(); T::make(2)] { - | ^^^^^^^^^^^^^^^^ cannot normalize `process::{constant#0}` - -error[E0284]: type annotations needed: cannot normalize `Struct::field::{constant#0}` - --> $DIR/const-trait-bounds.rs:20:12 - | -LL | field: [u32; T::make(P)], - | ^^^^^^^^^^^^^^^^^ cannot normalize `Struct::field::{constant#0}` - -error[E0284]: type annotations needed: cannot normalize `process::{constant#1}` - --> $DIR/const-trait-bounds.rs:13:5 - | -LL | input - | ^^^^^ cannot normalize `process::{constant#1}` - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0284`. From 1ba72db24241d590ea0d009d7e07fe49ea79579c Mon Sep 17 00:00:00 2001 From: ismailarilik Date: Tue, 12 Nov 2024 07:28:23 +0300 Subject: [PATCH 22/22] test(configure): cover `parse_args` in `src/bootstrap/configure.py` --- src/bootstrap/bootstrap_test.py | 47 +++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/bootstrap/bootstrap_test.py b/src/bootstrap/bootstrap_test.py index 706f2c5bf0701..70ed12b96e875 100644 --- a/src/bootstrap/bootstrap_test.py +++ b/src/bootstrap/bootstrap_test.py @@ -5,6 +5,7 @@ from __future__ import absolute_import, division, print_function import os import unittest +from unittest.mock import patch import tempfile import hashlib import sys @@ -99,6 +100,52 @@ def test_same_dates(self): self.assertFalse(self.build.program_out_of_date(self.rustc_stamp_path, self.key)) +class ParseArgsInConfigure(unittest.TestCase): + """Test if `parse_args` function in `configure.py` works properly""" + @patch("configure.err") + def test_unknown_args(self, err): + # It should be print an error message if the argument doesn't start with '--' + configure.parse_args(["enable-full-tools"]) + err.assert_called_with("Option 'enable-full-tools' is not recognized") + err.reset_mock() + # It should be print an error message if the argument is not recognized + configure.parse_args(["--some-random-flag"]) + err.assert_called_with("Option '--some-random-flag' is not recognized") + + @patch("configure.err") + def test_need_value_args(self, err): + """It should print an error message if a required argument value is missing""" + configure.parse_args(["--target"]) + err.assert_called_with("Option '--target' needs a value (--target=val)") + + @patch("configure.err") + def test_option_checking(self, err): + # Options should be checked even if `--enable-option-checking` is not passed + configure.parse_args(["--target"]) + err.assert_called_with("Option '--target' needs a value (--target=val)") + err.reset_mock() + # Options should be checked if `--enable-option-checking` is passed + configure.parse_args(["--enable-option-checking", "--target"]) + err.assert_called_with("Option '--target' needs a value (--target=val)") + err.reset_mock() + # Options should not be checked if `--disable-option-checking` is passed + configure.parse_args(["--disable-option-checking", "--target"]) + err.assert_not_called() + + @patch("configure.parse_example_config", lambda known_args, _: known_args) + def test_known_args(self): + # It should contain known and correct arguments + known_args = configure.parse_args(["--enable-full-tools"]) + self.assertTrue(known_args["full-tools"][0][1]) + known_args = configure.parse_args(["--disable-full-tools"]) + self.assertFalse(known_args["full-tools"][0][1]) + # It should contain known arguments and their values + known_args = configure.parse_args(["--target=x86_64-unknown-linux-gnu"]) + self.assertEqual(known_args["target"][0][1], "x86_64-unknown-linux-gnu") + known_args = configure.parse_args(["--target", "x86_64-unknown-linux-gnu"]) + self.assertEqual(known_args["target"][0][1], "x86_64-unknown-linux-gnu") + + class GenerateAndParseConfig(unittest.TestCase): """Test that we can serialize and deserialize a config.toml file""" def test_no_args(self):