diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c6c816eec622..445658d1b2198 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -431,7 +431,7 @@ jobs: - name: x86_64-mingw-1 env: SCRIPT: make ci-mingw-subset-1 - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu" + RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler" CUSTOM_MINGW: 1 NO_DEBUG_ASSERTIONS: 1 NO_LLVM_ASSERTIONS: 1 @@ -439,7 +439,7 @@ jobs: - name: x86_64-mingw-2 env: SCRIPT: make ci-mingw-subset-2 - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu" + RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler" CUSTOM_MINGW: 1 os: windows-latest-xl - name: dist-x86_64-msvc diff --git a/Cargo.lock b/Cargo.lock index f94d95d2dc838..d4e718cb603e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -427,9 +427,9 @@ dependencies = [ [[package]] name = "chalk-derive" -version = "0.14.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d463e01905d607e181de72e8608721d3269f29176c9a14ce037011316ae7131d" +checksum = "c1df0dbb57d74b4acd20f20fa66ab2acd09776b79eaeb9d8f947b2f3e01c40bf" dependencies = [ "proc-macro2", "quote", @@ -439,21 +439,22 @@ dependencies = [ [[package]] name = "chalk-engine" -version = "0.14.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efaf428f5398d36284f79690cf988762b7c091249f50a6c11db613a46c057000" +checksum = "fb7c65a13f32f02aba8f1d9a37f206af615f77ac564624b81a4c593c6c1735b9" dependencies = [ "chalk-derive", "chalk-ir", + "chalk-solve", "rustc-hash", "tracing", ] [[package]] name = "chalk-ir" -version = "0.14.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3fdc1e9f68498ffe80f4a23b0b95f1ca6fb21d5a4c9b0c085fab3ca712bdbe" +checksum = "44361a25dbdb1dc428f56ad7a3c21ba9ca12f3225c26a47919ff6fcb10a583d4" dependencies = [ "chalk-derive", "lazy_static", @@ -461,18 +462,19 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.14.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9fd4102807b7ebe8fb034fa0f488c5656e1966d3261b558b81a08d519cdb29" +checksum = "a886da37a0dc457057d86f78f026f7a09c6d8088aa13f4f4127fdb8dc80119a3" dependencies = [ "chalk-derive", - "chalk-engine", "chalk-ir", "ena", "itertools 0.9.0", "petgraph", "rustc-hash", "tracing", + "tracing-subscriber", + "tracing-tree", ] [[package]] @@ -4038,6 +4040,7 @@ dependencies = [ name = "rustc_traits" version = "0.0.0" dependencies = [ + "chalk-engine", "chalk-ir", "chalk-solve", "rustc_ast", @@ -4996,6 +4999,27 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "tracing-log" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e0f8c7178e13481ff6765bd169b33e8d554c5d2bbede5e32c356194be02b9b9" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6ccba2f8f16e0ed268fc765d9b7ff22e965e7185d32f8f1ec8294fe17d86e79" +dependencies = [ + "serde", + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.2.11" @@ -5003,14 +5027,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abd165311cc4d7a555ad11cc77a37756df836182db0d81aac908c8184c584f40" dependencies = [ "ansi_term 0.12.1", + "chrono", "lazy_static", "matchers", "parking_lot 0.11.0", "regex", + "serde", + "serde_json", "sharded-slab", "smallvec 1.4.2", "thread_local", "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "tracing-tree" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1a3dc4774db3a6b2d66a4f8d8de670e874ec3ed55615860c994927419b32c5f" +dependencies = [ + "ansi_term 0.12.1", + "atty", + "chrono", + "termcolor", + "tracing", + "tracing-subscriber", ] [[package]] diff --git a/README.md b/README.md index a7e23d8ac2caa..6cf9577d3330e 100644 --- a/README.md +++ b/README.md @@ -243,6 +243,8 @@ The Rust community congregates in a few places: If you are interested in contributing to the Rust project, please take a look at the [Getting Started][gettingstarted] guide in the [rustc-dev-guide]. +[rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org + ## License Rust is primarily distributed under the terms of both the MIT license diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 5a82cbf2997df..302a907538c84 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -27,7 +27,7 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } byteorder = { version = "1.3" } -chalk-ir = "0.14.0" +chalk-ir = "0.21.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } measureme = "0.7.1" rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_middle/src/traits/chalk.rs b/compiler/rustc_middle/src/traits/chalk.rs index 405af8cb2406c..763b078e7703e 100644 --- a/compiler/rustc_middle/src/traits/chalk.rs +++ b/compiler/rustc_middle/src/traits/chalk.rs @@ -75,6 +75,7 @@ impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> { type InternedQuantifiedWhereClauses = Vec>; type InternedVariableKinds = Vec>; type InternedCanonicalVarKinds = Vec>; + type InternedConstraints = Vec>>; type DefId = DefId; type InternedAdtId = &'tcx AdtDef; type Identifier = (); @@ -108,8 +109,42 @@ impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> { application_ty: &chalk_ir::ApplicationTy, fmt: &mut fmt::Formatter<'_>, ) -> Option { - let chalk_ir::ApplicationTy { name, substitution } = application_ty; - Some(write!(fmt, "{:?}{:?}", name, chalk_ir::debug::Angle(substitution.interned()))) + match application_ty.name { + chalk_ir::TypeName::Ref(mutbl) => { + let data = application_ty.substitution.interned(); + match (&**data[0].interned(), &**data[1].interned()) { + ( + chalk_ir::GenericArgData::Lifetime(lifetime), + chalk_ir::GenericArgData::Ty(ty), + ) => Some(match mutbl { + chalk_ir::Mutability::Not => write!(fmt, "(&{:?} {:?})", lifetime, ty), + chalk_ir::Mutability::Mut => write!(fmt, "(&{:?} mut {:?})", lifetime, ty), + }), + _ => unreachable!(), + } + } + chalk_ir::TypeName::Array => { + let data = application_ty.substitution.interned(); + match (&**data[0].interned(), &**data[1].interned()) { + (chalk_ir::GenericArgData::Ty(ty), chalk_ir::GenericArgData::Const(len)) => { + Some(write!(fmt, "[{:?}; {:?}]", ty, len)) + } + _ => unreachable!(), + } + } + chalk_ir::TypeName::Slice => { + let data = application_ty.substitution.interned(); + let ty = match &**data[0].interned() { + chalk_ir::GenericArgData::Ty(t) => t, + _ => unreachable!(), + }; + Some(write!(fmt, "[{:?}]", ty)) + } + _ => { + let chalk_ir::ApplicationTy { name, substitution } = application_ty; + Some(write!(fmt, "{:?}{:?}", name, chalk_ir::debug::Angle(substitution.interned()))) + } + } } fn debug_substitution( @@ -321,6 +356,20 @@ impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> { ) -> &'a [chalk_ir::CanonicalVarKind] { canonical_var_kinds } + + fn intern_constraints( + &self, + data: impl IntoIterator>, E>>, + ) -> Result { + data.into_iter().collect::, _>>() + } + + fn constraints_data<'a>( + &self, + constraints: &'a Self::InternedConstraints, + ) -> &'a [chalk_ir::InEnvironment>] { + constraints + } } impl<'tcx> chalk_ir::interner::HasInterner for RustInterner<'tcx> { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 832cde86d0b7b..392070839dc2a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -250,13 +250,23 @@ impl CheckAttrVisitor<'tcx> { None } } + Target::AssocConst => { + let parent_hir_id = self.tcx.hir().get_parent_item(hir_id); + let containing_item = self.tcx.hir().expect_item(parent_hir_id); + // We can't link to trait impl's consts. + let err = "associated constant in trait implementation block"; + match containing_item.kind { + ItemKind::Impl { of_trait: Some(_), .. } => Some(err), + _ => None, + } + } _ => None, } { self.tcx .sess .struct_span_err( meta.span(), - &format!("`#[doc(alias = \"...\")]` isn't allowed on {}", err,), + &format!("`#[doc(alias = \"...\")]` isn't allowed on {}", err), ) .emit(); } diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml index 2d63fc51220e1..3571ff17f31be 100644 --- a/compiler/rustc_traits/Cargo.toml +++ b/compiler/rustc_traits/Cargo.toml @@ -12,8 +12,9 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } -chalk-ir = "0.14.0" -chalk-solve = "0.14.0" +chalk-ir = "0.21.0" +chalk-solve = "0.21.0" +chalk-engine = "0.21.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } rustc_infer = { path = "../rustc_infer" } rustc_trait_selection = { path = "../rustc_trait_selection" } diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index c2f2469a1408d..7cc567dabb28f 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -8,20 +8,22 @@ use rustc_middle::traits::ChalkRustInterner as RustInterner; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; -use rustc_middle::ty::{self, AssocItemContainer, AssocKind, TyCtxt}; +use rustc_middle::ty::{self, AssocItemContainer, AssocKind, TyCtxt, TypeFoldable}; use rustc_hir::def_id::DefId; +use rustc_hir::Unsafety; use rustc_span::symbol::sym; use std::fmt; use std::sync::Arc; -use crate::chalk::lowering::LowerInto; +use crate::chalk::lowering::{self, LowerInto}; pub struct RustIrDatabase<'tcx> { - pub tcx: TyCtxt<'tcx>, - pub interner: RustInterner<'tcx>, + pub(crate) interner: RustInterner<'tcx>, + pub(crate) restatic_placeholder: ty::Region<'tcx>, + pub(crate) reempty_placeholder: ty::Region<'tcx>, } impl fmt::Debug for RustIrDatabase<'_> { @@ -30,6 +32,26 @@ impl fmt::Debug for RustIrDatabase<'_> { } } +impl<'tcx> RustIrDatabase<'tcx> { + fn where_clauses_for( + &self, + def_id: DefId, + bound_vars: SubstsRef<'tcx>, + ) -> Vec>> { + let predicates = self.interner.tcx.predicates_of(def_id).predicates; + let mut regions_substitutor = lowering::RegionsSubstitutor::new( + self.interner.tcx, + self.restatic_placeholder, + self.reempty_placeholder, + ); + predicates + .iter() + .map(|(wc, _)| wc.subst(self.interner.tcx, bound_vars)) + .map(|wc| wc.fold_with(&mut regions_substitutor)) + .filter_map(|wc| LowerInto::>>>::lower_into(wc, &self.interner)).collect() + } +} + impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'tcx> { fn interner(&self) -> &RustInterner<'tcx> { &self.interner @@ -40,7 +62,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t assoc_type_id: chalk_ir::AssocTypeId>, ) -> Arc>> { let def_id = assoc_type_id.0; - let assoc_item = self.tcx.associated_item(def_id); + let assoc_item = self.interner.tcx.associated_item(def_id); let trait_def_id = match assoc_item.container { AssocItemContainer::TraitContainer(def_id) => def_id, _ => unimplemented!("Not possible??"), @@ -49,16 +71,12 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t AssocKind::Type => {} _ => unimplemented!("Not possible??"), } - let bound_vars = bound_vars_for_item(self.tcx, def_id); + let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); let binders = binders_for(&self.interner, bound_vars); // FIXME(chalk): this really isn't right I don't think. The functions // for GATs are a bit hard to figure out. Are these supposed to be where // clauses or bounds? - let predicates = self.tcx.predicates_defined_on(def_id).predicates; - let where_clauses: Vec<_> = predicates - .iter() - .map(|(wc, _)| wc.subst(self.tcx, &bound_vars)) - .filter_map(|wc| LowerInto::>>>::lower_into(wc, &self.interner)).collect(); + let where_clauses = self.where_clauses_for(def_id, bound_vars); Arc::new(chalk_solve::rust_ir::AssociatedTyDatum { trait_id: chalk_ir::TraitId(trait_def_id), @@ -76,16 +94,15 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t trait_id: chalk_ir::TraitId>, ) -> Arc>> { let def_id = trait_id.0; - let trait_def = self.tcx.trait_def(def_id); + let trait_def = self.interner.tcx.trait_def(def_id); - let bound_vars = bound_vars_for_item(self.tcx, def_id); + let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); let binders = binders_for(&self.interner, bound_vars); - let predicates = self.tcx.predicates_defined_on(def_id).predicates; - let where_clauses: Vec<_> = predicates - .iter() - .map(|(wc, _)| wc.subst(self.tcx, &bound_vars)) - .filter_map(|wc| LowerInto::>>>::lower_into(wc, &self.interner)).collect(); + + let where_clauses = self.where_clauses_for(def_id, bound_vars); + let associated_ty_ids: Vec<_> = self + .interner .tcx .associated_items(def_id) .in_definition_order() @@ -93,24 +110,47 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t .map(|i| chalk_ir::AssocTypeId(i.def_id)) .collect(); - let well_known = - if self.tcx.lang_items().sized_trait().map(|t| def_id == t).unwrap_or(false) { - Some(chalk_solve::rust_ir::WellKnownTrait::Sized) - } else if self.tcx.lang_items().copy_trait().map(|t| def_id == t).unwrap_or(false) { - Some(chalk_solve::rust_ir::WellKnownTrait::Copy) - } else if self.tcx.lang_items().clone_trait().map(|t| def_id == t).unwrap_or(false) { - Some(chalk_solve::rust_ir::WellKnownTrait::Clone) - } else if self.tcx.lang_items().drop_trait().map(|t| def_id == t).unwrap_or(false) { - Some(chalk_solve::rust_ir::WellKnownTrait::Drop) - } else if self.tcx.lang_items().fn_trait().map(|t| def_id == t).unwrap_or(false) { - Some(chalk_solve::rust_ir::WellKnownTrait::Fn) - } else if self.tcx.lang_items().fn_once_trait().map(|t| def_id == t).unwrap_or(false) { - Some(chalk_solve::rust_ir::WellKnownTrait::FnOnce) - } else if self.tcx.lang_items().fn_mut_trait().map(|t| def_id == t).unwrap_or(false) { - Some(chalk_solve::rust_ir::WellKnownTrait::FnMut) - } else { - None - }; + let well_known = if self + .interner + .tcx + .lang_items() + .sized_trait() + .map(|t| def_id == t) + .unwrap_or(false) + { + Some(chalk_solve::rust_ir::WellKnownTrait::Sized) + } else if self.interner.tcx.lang_items().copy_trait().map(|t| def_id == t).unwrap_or(false) + { + Some(chalk_solve::rust_ir::WellKnownTrait::Copy) + } else if self.interner.tcx.lang_items().clone_trait().map(|t| def_id == t).unwrap_or(false) + { + Some(chalk_solve::rust_ir::WellKnownTrait::Clone) + } else if self.interner.tcx.lang_items().drop_trait().map(|t| def_id == t).unwrap_or(false) + { + Some(chalk_solve::rust_ir::WellKnownTrait::Drop) + } else if self.interner.tcx.lang_items().fn_trait().map(|t| def_id == t).unwrap_or(false) { + Some(chalk_solve::rust_ir::WellKnownTrait::Fn) + } else if self + .interner + .tcx + .lang_items() + .fn_once_trait() + .map(|t| def_id == t) + .unwrap_or(false) + { + Some(chalk_solve::rust_ir::WellKnownTrait::FnOnce) + } else if self + .interner + .tcx + .lang_items() + .fn_mut_trait() + .map(|t| def_id == t) + .unwrap_or(false) + { + Some(chalk_solve::rust_ir::WellKnownTrait::FnMut) + } else { + None + }; Arc::new(chalk_solve::rust_ir::TraitDatum { id: trait_id, binders: chalk_ir::Binders::new( @@ -121,7 +161,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t auto: trait_def.has_auto_impl, marker: trait_def.is_marker, upstream: !def_id.is_local(), - fundamental: self.tcx.has_attr(def_id, sym::fundamental), + fundamental: self.interner.tcx.has_attr(def_id, sym::fundamental), non_enumerable: true, coinductive: false, }, @@ -136,45 +176,50 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t ) -> Arc>> { let adt_def = adt_id.0; - let bound_vars = bound_vars_for_item(self.tcx, adt_def.did); + let bound_vars = bound_vars_for_item(self.interner.tcx, adt_def.did); let binders = binders_for(&self.interner, bound_vars); - let predicates = self.tcx.predicates_of(adt_def.did).predicates; - let where_clauses: Vec<_> = predicates + let where_clauses = self.where_clauses_for(adt_def.did, bound_vars); + + let variants: Vec<_> = adt_def + .variants .iter() - .map(|(wc, _)| wc.subst(self.tcx, bound_vars)) - .filter_map(|wc| LowerInto::>>>::lower_into(wc, &self.interner)) - .collect(); - let fields = match adt_def.adt_kind() { - ty::AdtKind::Struct | ty::AdtKind::Union => { - let variant = adt_def.non_enum_variant(); - variant + .map(|variant| chalk_solve::rust_ir::AdtVariantDatum { + fields: variant .fields .iter() - .map(|field| { - self.tcx - .type_of(field.did) - .subst(self.tcx, bound_vars) - .lower_into(&self.interner) - }) - .collect() - } - // FIXME(chalk): handle enums; force_impl_for requires this - ty::AdtKind::Enum => vec![], - }; - let struct_datum = Arc::new(chalk_solve::rust_ir::AdtDatum { + .map(|field| field.ty(self.interner.tcx, bound_vars).lower_into(&self.interner)) + .collect(), + }) + .collect(); + Arc::new(chalk_solve::rust_ir::AdtDatum { id: adt_id, binders: chalk_ir::Binders::new( binders, - chalk_solve::rust_ir::AdtDatumBound { fields, where_clauses }, + chalk_solve::rust_ir::AdtDatumBound { variants, where_clauses }, ), flags: chalk_solve::rust_ir::AdtFlags { upstream: !adt_def.did.is_local(), fundamental: adt_def.is_fundamental(), phantom_data: adt_def.is_phantom_data(), }, - }); - struct_datum + kind: match adt_def.adt_kind() { + ty::AdtKind::Struct => chalk_solve::rust_ir::AdtKind::Struct, + ty::AdtKind::Union => chalk_solve::rust_ir::AdtKind::Union, + ty::AdtKind::Enum => chalk_solve::rust_ir::AdtKind::Enum, + }, + }) + } + + fn adt_repr( + &self, + adt_id: chalk_ir::AdtId>, + ) -> chalk_solve::rust_ir::AdtRepr { + let adt_def = adt_id.0; + chalk_solve::rust_ir::AdtRepr { + repr_c: adt_def.repr.c(), + repr_packed: adt_def.repr.packed(), + } } fn fn_def_datum( @@ -182,30 +227,25 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t fn_def_id: chalk_ir::FnDefId>, ) -> Arc>> { let def_id = fn_def_id.0; - let bound_vars = bound_vars_for_item(self.tcx, def_id); + let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); let binders = binders_for(&self.interner, bound_vars); - let predicates = self.tcx.predicates_defined_on(def_id).predicates; - let where_clauses: Vec<_> = predicates - .iter() - .map(|(wc, _)| wc.subst(self.tcx, &bound_vars)) - .filter_map(|wc| LowerInto::>>>::lower_into(wc, &self.interner)).collect(); + let where_clauses = self.where_clauses_for(def_id, bound_vars); - let sig = self.tcx.fn_sig(def_id); - let inputs_and_output = sig.inputs_and_output(); + let sig = self.interner.tcx.fn_sig(def_id); let (inputs_and_output, iobinders, _) = crate::chalk::lowering::collect_bound_vars( &self.interner, - self.tcx, - &inputs_and_output, + self.interner.tcx, + &sig.inputs_and_output().subst(self.interner.tcx, bound_vars), ); let argument_types = inputs_and_output[..inputs_and_output.len() - 1] .iter() - .map(|t| t.subst(self.tcx, &bound_vars).lower_into(&self.interner)) + .map(|t| t.subst(self.interner.tcx, &bound_vars).lower_into(&self.interner)) .collect(); let return_type = inputs_and_output[inputs_and_output.len() - 1] - .subst(self.tcx, &bound_vars) + .subst(self.interner.tcx, &bound_vars) .lower_into(&self.interner); let bound = chalk_solve::rust_ir::FnDefDatumBound { @@ -218,6 +258,11 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t Arc::new(chalk_solve::rust_ir::FnDefDatum { id: fn_def_id, abi: sig.abi(), + safety: match sig.unsafety() { + Unsafety::Normal => chalk_ir::Safety::Safe, + Unsafety::Unsafe => chalk_ir::Safety::Unsafe, + }, + variadic: sig.c_variadic(), binders: chalk_ir::Binders::new(binders, bound), }) } @@ -227,17 +272,19 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t impl_id: chalk_ir::ImplId>, ) -> Arc>> { let def_id = impl_id.0; - let bound_vars = bound_vars_for_item(self.tcx, def_id); + let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); let binders = binders_for(&self.interner, bound_vars); - let trait_ref = self.tcx.impl_trait_ref(def_id).expect("not an impl"); - let trait_ref = trait_ref.subst(self.tcx, bound_vars); + let trait_ref = self.interner.tcx.impl_trait_ref(def_id).expect("not an impl"); + let trait_ref = trait_ref.subst(self.interner.tcx, bound_vars); + let mut regions_substitutor = lowering::RegionsSubstitutor::new( + self.interner.tcx, + self.restatic_placeholder, + self.reempty_placeholder, + ); + let trait_ref = trait_ref.fold_with(&mut regions_substitutor); - let predicates = self.tcx.predicates_of(def_id).predicates; - let where_clauses: Vec<_> = predicates - .iter() - .map(|(wc, _)| wc.subst(self.tcx, bound_vars)) - .filter_map(|wc| LowerInto::>>>::lower_into(wc, &self.interner)).collect(); + let where_clauses = self.where_clauses_for(def_id, bound_vars); let value = chalk_solve::rust_ir::ImplDatumBound { trait_ref: trait_ref.lower_into(&self.interner), @@ -256,6 +303,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t &self, trait_id: chalk_ir::TraitId>, parameters: &[chalk_ir::GenericArg>], + _binders: &chalk_ir::CanonicalVarKinds>, ) -> Vec>> { let def_id = trait_id.0; @@ -263,14 +311,20 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t // require us to be able to interconvert `Ty<'tcx>`, and we're // not there yet. - let all_impls = self.tcx.all_impls(def_id); + let all_impls = self.interner.tcx.all_impls(def_id); let matched_impls = all_impls.filter(|impl_def_id| { use chalk_ir::could_match::CouldMatch; - let trait_ref = self.tcx.impl_trait_ref(*impl_def_id).unwrap(); - let bound_vars = bound_vars_for_item(self.tcx, *impl_def_id); + let trait_ref = self.interner.tcx.impl_trait_ref(*impl_def_id).unwrap(); + let bound_vars = bound_vars_for_item(self.interner.tcx, *impl_def_id); let self_ty = trait_ref.self_ty(); - let self_ty = self_ty.subst(self.tcx, bound_vars); + let self_ty = self_ty.subst(self.interner.tcx, bound_vars); + let mut regions_substitutor = lowering::RegionsSubstitutor::new( + self.interner.tcx, + self.restatic_placeholder, + self.reempty_placeholder, + ); + let self_ty = self_ty.fold_with(&mut regions_substitutor); let lowered_ty = self_ty.lower_into(&self.interner); parameters[0].assert_ty_ref(&self.interner).could_match(&self.interner, &lowered_ty) @@ -287,9 +341,9 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t ) -> bool { let trait_def_id = auto_trait_id.0; let adt_def = adt_id.0; - let all_impls = self.tcx.all_impls(trait_def_id); + let all_impls = self.interner.tcx.all_impls(trait_def_id); for impl_def_id in all_impls { - let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap(); + let trait_ref = self.interner.tcx.impl_trait_ref(impl_def_id).unwrap(); let self_ty = trait_ref.self_ty(); match *self_ty.kind() { ty::Adt(impl_adt_def, _) => { @@ -308,7 +362,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t associated_ty_id: chalk_solve::rust_ir::AssociatedTyValueId>, ) -> Arc>> { let def_id = associated_ty_id.0; - let assoc_item = self.tcx.associated_item(def_id); + let assoc_item = self.interner.tcx.associated_item(def_id); let impl_id = match assoc_item.container { AssocItemContainer::TraitContainer(def_id) => def_id, _ => unimplemented!("Not possible??"), @@ -317,9 +371,9 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t AssocKind::Type => {} _ => unimplemented!("Not possible??"), } - let bound_vars = bound_vars_for_item(self.tcx, def_id); + let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); let binders = binders_for(&self.interner, bound_vars); - let ty = self.tcx.type_of(def_id); + let ty = self.interner.tcx.type_of(def_id); Arc::new(chalk_solve::rust_ir::AssociatedTyValue { impl_id: chalk_ir::ImplId(impl_id), @@ -346,78 +400,20 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t &self, opaque_ty_id: chalk_ir::OpaqueTyId>, ) -> Arc>> { - let bound_vars = bound_vars_for_item(self.tcx, opaque_ty_id.0); + let bound_vars = bound_vars_for_item(self.interner.tcx, opaque_ty_id.0); let binders = binders_for(&self.interner, bound_vars); - let predicates = self.tcx.predicates_defined_on(opaque_ty_id.0).predicates; - let where_clauses: Vec<_> = predicates - .iter() - .map(|(wc, _)| wc.subst(self.tcx, &bound_vars)) - .filter_map(|wc| LowerInto::>>>::lower_into(wc, &self.interner)).collect(); + let where_clauses = self.where_clauses_for(opaque_ty_id.0, bound_vars); let value = chalk_solve::rust_ir::OpaqueTyDatumBound { - bounds: chalk_ir::Binders::new(binders, where_clauses), + bounds: chalk_ir::Binders::new(binders.clone(), vec![]), + where_clauses: chalk_ir::Binders::new(binders, where_clauses), }; Arc::new(chalk_solve::rust_ir::OpaqueTyDatum { opaque_ty_id, - bound: chalk_ir::Binders::new(chalk_ir::VariableKinds::new(&self.interner), value), + bound: chalk_ir::Binders::empty(&self.interner, value), }) } - /// Since Chalk can't handle all Rust types currently, we have to handle - /// some specially for now. Over time, these `Some` returns will change to - /// `None` and eventually this function will be removed. - fn force_impl_for( - &self, - well_known: chalk_solve::rust_ir::WellKnownTrait, - ty: &chalk_ir::TyData>, - ) -> Option { - use chalk_ir::TyData::*; - match well_known { - chalk_solve::rust_ir::WellKnownTrait::Sized => match ty { - Apply(apply) => match apply.name { - chalk_ir::TypeName::Adt(chalk_ir::AdtId(adt_def)) => match adt_def.adt_kind() { - ty::AdtKind::Struct | ty::AdtKind::Union => None, - ty::AdtKind::Enum => { - let constraint = self.tcx.adt_sized_constraint(adt_def.did); - if !constraint.0.is_empty() { unimplemented!() } else { Some(true) } - } - }, - _ => None, - }, - Dyn(_) - | Alias(_) - | Placeholder(_) - | Function(_) - | InferenceVar(_, _) - | BoundVar(_) => None, - }, - chalk_solve::rust_ir::WellKnownTrait::Copy - | chalk_solve::rust_ir::WellKnownTrait::Clone => match ty { - Apply(apply) => match apply.name { - chalk_ir::TypeName::Adt(chalk_ir::AdtId(adt_def)) => match adt_def.adt_kind() { - ty::AdtKind::Struct | ty::AdtKind::Union => None, - ty::AdtKind::Enum => { - let constraint = self.tcx.adt_sized_constraint(adt_def.did); - if !constraint.0.is_empty() { unimplemented!() } else { Some(true) } - } - }, - _ => None, - }, - Dyn(_) - | Alias(_) - | Placeholder(_) - | Function(_) - | InferenceVar(_, _) - | BoundVar(_) => None, - }, - chalk_solve::rust_ir::WellKnownTrait::Drop => None, - chalk_solve::rust_ir::WellKnownTrait::Fn => None, - chalk_solve::rust_ir::WellKnownTrait::FnMut => None, - chalk_solve::rust_ir::WellKnownTrait::FnOnce => None, - chalk_solve::rust_ir::WellKnownTrait::Unsize => None, - } - } - fn program_clauses_for_env( &self, environment: &chalk_ir::Environment>, @@ -431,20 +427,20 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t ) -> Option>> { use chalk_solve::rust_ir::WellKnownTrait::*; let def_id = match well_known_trait { - Sized => self.tcx.lang_items().sized_trait(), - Copy => self.tcx.lang_items().copy_trait(), - Clone => self.tcx.lang_items().clone_trait(), - Drop => self.tcx.lang_items().drop_trait(), - Fn => self.tcx.lang_items().fn_trait(), - FnMut => self.tcx.lang_items().fn_mut_trait(), - FnOnce => self.tcx.lang_items().fn_once_trait(), - Unsize => self.tcx.lang_items().unsize_trait(), + Sized => self.interner.tcx.lang_items().sized_trait(), + Copy => self.interner.tcx.lang_items().copy_trait(), + Clone => self.interner.tcx.lang_items().clone_trait(), + Drop => self.interner.tcx.lang_items().drop_trait(), + Fn => self.interner.tcx.lang_items().fn_trait(), + FnMut => self.interner.tcx.lang_items().fn_mut_trait(), + FnOnce => self.interner.tcx.lang_items().fn_once_trait(), + Unsize => self.interner.tcx.lang_items().unsize_trait(), }; def_id.map(chalk_ir::TraitId) } fn is_object_safe(&self, trait_id: chalk_ir::TraitId>) -> bool { - self.tcx.is_object_safe(trait_id.0) + self.interner.tcx.is_object_safe(trait_id.0) } fn hidden_opaque_type( @@ -452,7 +448,10 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t _id: chalk_ir::OpaqueTyId>, ) -> chalk_ir::Ty> { // FIXME(chalk): actually get hidden ty - self.tcx.mk_ty(ty::Tuple(self.tcx.intern_substs(&[]))).lower_into(&self.interner) + self.interner + .tcx + .mk_ty(ty::Tuple(self.interner.tcx.intern_substs(&[]))) + .lower_into(&self.interner) } fn closure_kind( @@ -460,7 +459,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t _closure_id: chalk_ir::ClosureId>, substs: &chalk_ir::Substitution>, ) -> chalk_solve::rust_ir::ClosureKind { - let kind = &substs.parameters(&self.interner)[substs.len(&self.interner) - 3]; + let kind = &substs.as_slice(&self.interner)[substs.len(&self.interner) - 3]; match kind.assert_ty_ref(&self.interner).data(&self.interner) { chalk_ir::TyData::Apply(apply) => match apply.name { chalk_ir::TypeName::Scalar(scalar) => match scalar { @@ -484,10 +483,10 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t substs: &chalk_ir::Substitution>, ) -> chalk_ir::Binders>> { - let sig = &substs.parameters(&self.interner)[substs.len(&self.interner) - 2]; + let sig = &substs.as_slice(&self.interner)[substs.len(&self.interner) - 2]; match sig.assert_ty_ref(&self.interner).data(&self.interner) { chalk_ir::TyData::Function(f) => { - let substitution = f.substitution.parameters(&self.interner); + let substitution = f.substitution.as_slice(&self.interner); let return_type = substitution.last().unwrap().assert_ty_ref(&self.interner).clone(); // Closure arguments are tupled @@ -506,7 +505,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t }; chalk_ir::Binders::new( - chalk_ir::VariableKinds::from( + chalk_ir::VariableKinds::from_iter( &self.interner, (0..f.num_binders).map(|_| chalk_ir::VariableKind::Lifetime), ), @@ -523,7 +522,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t substs: &chalk_ir::Substitution>, ) -> chalk_ir::Binders>> { let inputs_and_output = self.closure_inputs_and_output(_closure_id, substs); - let tuple = substs.parameters(&self.interner).last().unwrap().assert_ty_ref(&self.interner); + let tuple = substs.as_slice(&self.interner).last().unwrap().assert_ty_ref(&self.interner); inputs_and_output.map_ref(|_| tuple.clone()) } @@ -532,8 +531,8 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t _closure_id: chalk_ir::ClosureId>, substs: &chalk_ir::Substitution>, ) -> chalk_ir::Substitution> { - let substitution = &substs.parameters(&self.interner)[0..substs.len(&self.interner) - 3]; - chalk_ir::Substitution::from(&self.interner, substitution) + let substitution = &substs.as_slice(&self.interner)[0..substs.len(&self.interner) - 3]; + chalk_ir::Substitution::from_iter(&self.interner, substitution) } } @@ -573,7 +572,7 @@ fn binders_for<'tcx>( interner: &RustInterner<'tcx>, bound_vars: SubstsRef<'tcx>, ) -> chalk_ir::VariableKinds> { - chalk_ir::VariableKinds::from( + chalk_ir::VariableKinds::from_iter( interner, bound_vars.iter().map(|arg| match arg.unpack() { ty::subst::GenericArgKind::Lifetime(_re) => chalk_ir::VariableKind::Lifetime, diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 779540ecd2493..a67bd492a39e7 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -56,7 +56,13 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Substitution>> for Subst self, interner: &RustInterner<'tcx>, ) -> chalk_ir::Substitution> { - chalk_ir::Substitution::from(interner, self.iter().map(|s| s.lower_into(interner))) + chalk_ir::Substitution::from_iter(interner, self.iter().map(|s| s.lower_into(interner))) + } +} + +impl<'tcx> LowerInto<'tcx, SubstsRef<'tcx>> for &chalk_ir::Substitution> { + fn lower_into(self, interner: &RustInterner<'tcx>) -> SubstsRef<'tcx> { + interner.tcx.mk_substs(self.iter(interner).map(|subst| subst.lower_into(interner))) } } @@ -76,78 +82,29 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment, ) -> chalk_ir::InEnvironment>> { - let clauses = self.environment.into_iter().filter_map(|clause| match clause { + let clauses = self.environment.into_iter().map(|clause| match clause { ChalkEnvironmentClause::Predicate(predicate) => { - // FIXME(chalk): forall - match predicate.bound_atom(interner.tcx).skip_binder() { - ty::PredicateAtom::Trait(predicate, _) => { - let predicate = ty::Binder::bind(predicate); - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &predicate); - - Some( - chalk_ir::ProgramClauseData(chalk_ir::Binders::new( - binders, - chalk_ir::ProgramClauseImplication { - consequence: chalk_ir::DomainGoal::FromEnv( - chalk_ir::FromEnv::Trait( - predicate.trait_ref.lower_into(interner), - ), - ), - conditions: chalk_ir::Goals::new(interner), - priority: chalk_ir::ClausePriority::High, - }, - )) - .intern(interner), - ) - } - ty::PredicateAtom::RegionOutlives(predicate) => { - let predicate = ty::Binder::bind(predicate); - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &predicate); - - Some( - chalk_ir::ProgramClauseData(chalk_ir::Binders::new( - binders, - chalk_ir::ProgramClauseImplication { - consequence: chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::LifetimeOutlives( - chalk_ir::LifetimeOutlives { - a: predicate.0.lower_into(interner), - b: predicate.1.lower_into(interner), - }, - ), - ), - conditions: chalk_ir::Goals::new(interner), - priority: chalk_ir::ClausePriority::High, - }, - )) - .intern(interner), - ) - } - // FIXME(chalk): need to add TypeOutlives - ty::PredicateAtom::TypeOutlives(_) => None, - ty::PredicateAtom::Projection(predicate) => { - let predicate = ty::Binder::bind(predicate); - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &predicate); - - Some( - chalk_ir::ProgramClauseData(chalk_ir::Binders::new( - binders, - chalk_ir::ProgramClauseImplication { - consequence: chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::AliasEq( - predicate.lower_into(interner), - ), - ), - conditions: chalk_ir::Goals::new(interner), - priority: chalk_ir::ClausePriority::High, - }, - )) - .intern(interner), - ) - } + let (predicate, binders, _named_regions) = + collect_bound_vars(interner, interner.tcx, &predicate.bound_atom(interner.tcx)); + let consequence = match predicate { + ty::PredicateAtom::Trait(predicate, _) => chalk_ir::DomainGoal::FromEnv( + chalk_ir::FromEnv::Trait(predicate.trait_ref.lower_into(interner)), + ), + ty::PredicateAtom::RegionOutlives(predicate) => chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { + a: predicate.0.lower_into(interner), + b: predicate.1.lower_into(interner), + }), + ), + ty::PredicateAtom::TypeOutlives(predicate) => chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { + ty: predicate.0.lower_into(interner), + lifetime: predicate.1.lower_into(interner), + }), + ), + ty::PredicateAtom::Projection(predicate) => chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)), + ), ty::PredicateAtom::WellFormed(..) | ty::PredicateAtom::ObjectSafe(..) | ty::PredicateAtom::ClosureKind(..) @@ -156,27 +113,35 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment { bug!("unexpected predicate {}", predicate) } - } + }; + let value = chalk_ir::ProgramClauseImplication { + consequence, + conditions: chalk_ir::Goals::empty(interner), + priority: chalk_ir::ClausePriority::High, + constraints: chalk_ir::Constraints::empty(interner), + }; + chalk_ir::ProgramClauseData(chalk_ir::Binders::new(binders, value)).intern(interner) } - ChalkEnvironmentClause::TypeFromEnv(ty) => Some( + ChalkEnvironmentClause::TypeFromEnv(ty) => { chalk_ir::ProgramClauseData(chalk_ir::Binders::new( - chalk_ir::VariableKinds::new(interner), + chalk_ir::VariableKinds::empty(interner), chalk_ir::ProgramClauseImplication { consequence: chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty( ty.lower_into(interner).shifted_in(interner), )), - conditions: chalk_ir::Goals::new(interner), + conditions: chalk_ir::Goals::empty(interner), priority: chalk_ir::ClausePriority::High, + constraints: chalk_ir::Constraints::empty(interner), }, )) - .intern(interner), - ), + .intern(interner) + } }); let goal: chalk_ir::GoalData> = self.goal.lower_into(&interner); chalk_ir::InEnvironment { environment: chalk_ir::Environment { - clauses: chalk_ir::ProgramClauses::from(&interner, clauses), + clauses: chalk_ir::ProgramClauses::from_iter(&interner, clauses), }, goal: goal.intern(&interner), } @@ -185,63 +150,52 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predicate<'tcx> { fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData> { - // FIXME(chalk): forall - match self.bound_atom(interner.tcx).skip_binder() { + let (predicate, binders, _named_regions) = + collect_bound_vars(interner, interner.tcx, &self.bound_atom(interner.tcx)); + + let value = match predicate { ty::PredicateAtom::Trait(predicate, _) => { - ty::Binder::bind(predicate).lower_into(interner) + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner)), + )) } ty::PredicateAtom::RegionOutlives(predicate) => { - let predicate = ty::Binder::bind(predicate); - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &predicate); - - chalk_ir::GoalData::Quantified( - chalk_ir::QuantifierKind::ForAll, - chalk_ir::Binders::new( - binders, - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { - a: predicate.0.lower_into(interner), - b: predicate.1.lower_into(interner), - }), - )) - .intern(interner), - ), - ) + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { + a: predicate.0.lower_into(interner), + b: predicate.1.lower_into(interner), + }), + )) } - // FIXME(chalk): TypeOutlives - ty::PredicateAtom::TypeOutlives(_predicate) => { - chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) + ty::PredicateAtom::TypeOutlives(predicate) => { + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { + ty: predicate.0.lower_into(interner), + lifetime: predicate.1.lower_into(interner), + }), + )) } ty::PredicateAtom::Projection(predicate) => { - ty::Binder::bind(predicate).lower_into(interner) + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)), + )) } ty::PredicateAtom::WellFormed(arg) => match arg.unpack() { GenericArgKind::Type(ty) => match ty.kind() { // FIXME(chalk): In Chalk, a placeholder is WellFormed if it // `FromEnv`. However, when we "lower" Params, we don't update // the environment. - ty::Placeholder(..) => chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)), - - _ => { - let (ty, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &ty::Binder::bind(ty)); - - chalk_ir::GoalData::Quantified( - chalk_ir::QuantifierKind::ForAll, - chalk_ir::Binders::new( - binders, - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::WellFormed( - chalk_ir::WellFormed::Ty(ty.lower_into(interner)), - )) - .intern(interner), - ), - ) + ty::Placeholder(..) => { + chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) } + + _ => chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::WellFormed( + chalk_ir::WellFormed::Ty(ty.lower_into(interner)), + )), }, // FIXME(chalk): handle well formed consts GenericArgKind::Const(..) => { - chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) + chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) } GenericArgKind::Lifetime(lt) => bug!("unexpect well formed predicate: {:?}", lt), }, @@ -258,9 +212,14 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi | ty::PredicateAtom::Subtype(..) | ty::PredicateAtom::ConstEvaluatable(..) | ty::PredicateAtom::ConstEquate(..) => { - chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) + chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) } - } + }; + + chalk_ir::GoalData::Quantified( + chalk_ir::QuantifierKind::ForAll, + chalk_ir::Binders::new(binders, value.intern(interner)), + ) } } @@ -275,25 +234,6 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::TraitRef>> } } -impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> - for ty::PolyTraitPredicate<'tcx> -{ - fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData> { - let (ty, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, &self); - - chalk_ir::GoalData::Quantified( - chalk_ir::QuantifierKind::ForAll, - chalk_ir::Binders::new( - binders, - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::Implemented(ty.trait_ref.lower_into(interner)), - )) - .intern(interner), - ), - ) - } -} - impl<'tcx> LowerInto<'tcx, chalk_ir::AliasEq>> for rustc_middle::ty::ProjectionPredicate<'tcx> { @@ -305,25 +245,6 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::AliasEq>> } } -impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> - for ty::PolyProjectionPredicate<'tcx> -{ - fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData> { - let (ty, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, &self); - - chalk_ir::GoalData::Quantified( - chalk_ir::QuantifierKind::ForAll, - chalk_ir::Binders::new( - binders, - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::AliasEq(ty.lower_into(interner)), - )) - .intern(interner), - ), - ) - } -} - impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Ty> { use chalk_ir::TyData; @@ -364,7 +285,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { ast::FloatTy::F64 => float(chalk_ir::FloatTy::F64), }, Adt(def, substs) => apply(struct_ty(def.did), substs.lower_into(interner)), - Foreign(_def_id) => unimplemented!(), + // FIXME(chalk): lower Foreign + Foreign(def_id) => apply(chalk_ir::TypeName::FnDef(chalk_ir::FnDefId(def_id)), empty()), Str => apply(chalk_ir::TypeName::Str, empty()), Array(ty, len) => { let value = match len.val { @@ -381,7 +303,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { }; apply( chalk_ir::TypeName::Array, - chalk_ir::Substitution::from( + chalk_ir::Substitution::from_iter( interner, &[ chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner), @@ -415,7 +337,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { }; apply( name, - chalk_ir::Substitution::from( + chalk_ir::Substitution::from_iter( interner, &[ chalk_ir::GenericArgData::Lifetime(region.lower_into(interner)) @@ -432,14 +354,20 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { FnPtr(sig) => { let (inputs_and_outputs, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, &sig.inputs_and_output()); - TyData::Function(chalk_ir::Fn { + TyData::Function(chalk_ir::FnPointer { num_binders: binders.len(interner), - substitution: chalk_ir::Substitution::from( + substitution: chalk_ir::Substitution::from_iter( interner, inputs_and_outputs.iter().map(|ty| { chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner) }), ), + abi: sig.abi(), + safety: match sig.unsafety() { + rustc_hir::Unsafety::Normal => chalk_ir::Safety::Safe, + rustc_hir::Unsafety::Unsafe => chalk_ir::Safety::Unsafe, + }, + variadic: sig.c_variadic(), }) .intern(interner) } @@ -485,6 +413,111 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { } } +impl<'tcx> LowerInto<'tcx, Ty<'tcx>> for &chalk_ir::Ty> { + fn lower_into(self, interner: &RustInterner<'tcx>) -> Ty<'tcx> { + use chalk_ir::TyData; + use rustc_ast::ast; + + let kind = match self.data(interner) { + TyData::Apply(application_ty) => match application_ty.name { + chalk_ir::TypeName::Adt(struct_id) => { + ty::Adt(struct_id.0, application_ty.substitution.lower_into(interner)) + } + chalk_ir::TypeName::Scalar(scalar) => match scalar { + chalk_ir::Scalar::Bool => ty::Bool, + chalk_ir::Scalar::Char => ty::Char, + chalk_ir::Scalar::Int(int_ty) => match int_ty { + chalk_ir::IntTy::Isize => ty::Int(ast::IntTy::Isize), + chalk_ir::IntTy::I8 => ty::Int(ast::IntTy::I8), + chalk_ir::IntTy::I16 => ty::Int(ast::IntTy::I16), + chalk_ir::IntTy::I32 => ty::Int(ast::IntTy::I32), + chalk_ir::IntTy::I64 => ty::Int(ast::IntTy::I64), + chalk_ir::IntTy::I128 => ty::Int(ast::IntTy::I128), + }, + chalk_ir::Scalar::Uint(int_ty) => match int_ty { + chalk_ir::UintTy::Usize => ty::Uint(ast::UintTy::Usize), + chalk_ir::UintTy::U8 => ty::Uint(ast::UintTy::U8), + chalk_ir::UintTy::U16 => ty::Uint(ast::UintTy::U16), + chalk_ir::UintTy::U32 => ty::Uint(ast::UintTy::U32), + chalk_ir::UintTy::U64 => ty::Uint(ast::UintTy::U64), + chalk_ir::UintTy::U128 => ty::Uint(ast::UintTy::U128), + }, + chalk_ir::Scalar::Float(float_ty) => match float_ty { + chalk_ir::FloatTy::F32 => ty::Float(ast::FloatTy::F32), + chalk_ir::FloatTy::F64 => ty::Float(ast::FloatTy::F64), + }, + }, + chalk_ir::TypeName::Array => unimplemented!(), + chalk_ir::TypeName::FnDef(id) => { + ty::FnDef(id.0, application_ty.substitution.lower_into(interner)) + } + chalk_ir::TypeName::Closure(closure) => { + ty::Closure(closure.0, application_ty.substitution.lower_into(interner)) + } + chalk_ir::TypeName::Never => ty::Never, + chalk_ir::TypeName::Tuple(_size) => { + ty::Tuple(application_ty.substitution.lower_into(interner)) + } + chalk_ir::TypeName::Slice => ty::Slice( + application_ty.substitution.as_slice(interner)[0] + .ty(interner) + .unwrap() + .lower_into(interner), + ), + chalk_ir::TypeName::Raw(mutbl) => ty::RawPtr(ty::TypeAndMut { + ty: application_ty.substitution.as_slice(interner)[0] + .ty(interner) + .unwrap() + .lower_into(interner), + mutbl: match mutbl { + chalk_ir::Mutability::Mut => ast::Mutability::Mut, + chalk_ir::Mutability::Not => ast::Mutability::Not, + }, + }), + chalk_ir::TypeName::Ref(mutbl) => ty::Ref( + application_ty.substitution.as_slice(interner)[0] + .lifetime(interner) + .unwrap() + .lower_into(interner), + application_ty.substitution.as_slice(interner)[1] + .ty(interner) + .unwrap() + .lower_into(interner), + match mutbl { + chalk_ir::Mutability::Mut => ast::Mutability::Mut, + chalk_ir::Mutability::Not => ast::Mutability::Not, + }, + ), + chalk_ir::TypeName::Str => ty::Str, + chalk_ir::TypeName::OpaqueType(opaque_ty) => { + ty::Opaque(opaque_ty.0, application_ty.substitution.lower_into(interner)) + } + chalk_ir::TypeName::AssociatedType(assoc_ty) => ty::Projection(ty::ProjectionTy { + substs: application_ty.substitution.lower_into(interner), + item_def_id: assoc_ty.0, + }), + chalk_ir::TypeName::Error => unimplemented!(), + }, + TyData::Placeholder(placeholder) => ty::Placeholder(ty::Placeholder { + universe: ty::UniverseIndex::from_usize(placeholder.ui.counter), + name: ty::BoundVar::from_usize(placeholder.idx), + }), + TyData::Alias(_alias_ty) => unimplemented!(), + TyData::Function(_quantified_ty) => unimplemented!(), + TyData::BoundVar(_bound) => ty::Bound( + ty::DebruijnIndex::from_usize(_bound.debruijn.depth() as usize), + ty::BoundTy { + var: ty::BoundVar::from_usize(_bound.index), + kind: ty::BoundTyKind::Anon, + }, + ), + TyData::InferenceVar(_, _) => unimplemented!(), + TyData::Dyn(_) => unimplemented!(), + }; + interner.tcx.mk_ty(kind) + } +} + impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime>> for Region<'tcx> { fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Lifetime> { use rustc_middle::ty::RegionKind::*; @@ -522,6 +555,59 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime>> for Region<'t } } +impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime> { + fn lower_into(self, interner: &RustInterner<'tcx>) -> Region<'tcx> { + let kind = match self.data(interner) { + chalk_ir::LifetimeData::BoundVar(var) => ty::RegionKind::ReLateBound( + ty::DebruijnIndex::from_u32(var.debruijn.depth()), + ty::BoundRegion::BrAnon(var.index as u32), + ), + chalk_ir::LifetimeData::InferenceVar(_var) => unimplemented!(), + chalk_ir::LifetimeData::Placeholder(p) => { + ty::RegionKind::RePlaceholder(ty::Placeholder { + universe: ty::UniverseIndex::from_usize(p.ui.counter), + name: ty::BoundRegion::BrAnon(p.idx as u32), + }) + } + chalk_ir::LifetimeData::Phantom(_, _) => unimplemented!(), + }; + interner.tcx.mk_region(kind) + } +} + +impl<'tcx> LowerInto<'tcx, chalk_ir::Const>> for ty::Const<'tcx> { + fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Const> { + let ty = self.ty.lower_into(interner); + let value = match self.val { + ty::ConstKind::Value(val) => { + chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: val }) + } + ty::ConstKind::Bound(db, bound) => chalk_ir::ConstValue::BoundVar( + chalk_ir::BoundVar::new(chalk_ir::DebruijnIndex::new(db.as_u32()), bound.index()), + ), + _ => unimplemented!("Const not implemented. {:?}", self), + }; + chalk_ir::ConstData { ty, value }.intern(interner) + } +} + +impl<'tcx> LowerInto<'tcx, ty::Const<'tcx>> for &chalk_ir::Const> { + fn lower_into(self, interner: &RustInterner<'tcx>) -> ty::Const<'tcx> { + let data = self.data(interner); + let ty = data.ty.lower_into(interner); + let val = match data.value { + chalk_ir::ConstValue::BoundVar(var) => ty::ConstKind::Bound( + ty::DebruijnIndex::from_u32(var.debruijn.depth()), + ty::BoundVar::from_u32(var.index as u32), + ), + chalk_ir::ConstValue::InferenceVar(_var) => unimplemented!(), + chalk_ir::ConstValue::Placeholder(_p) => unimplemented!(), + chalk_ir::ConstValue::Concrete(c) => ty::ConstKind::Value(c.interned), + }; + ty::Const { ty, val } + } +} + impl<'tcx> LowerInto<'tcx, chalk_ir::GenericArg>> for GenericArg<'tcx> { fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GenericArg> { match self.unpack() { @@ -531,18 +617,35 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GenericArg>> for Generic ty::subst::GenericArgKind::Lifetime(lifetime) => { chalk_ir::GenericArgData::Lifetime(lifetime.lower_into(interner)) } - ty::subst::GenericArgKind::Const(_) => chalk_ir::GenericArgData::Ty( - chalk_ir::TyData::Apply(chalk_ir::ApplicationTy { - name: chalk_ir::TypeName::Tuple(0), - substitution: chalk_ir::Substitution::empty(interner), - }) - .intern(interner), - ), + ty::subst::GenericArgKind::Const(c) => { + chalk_ir::GenericArgData::Const(c.lower_into(interner)) + } } .intern(interner) } } +impl<'tcx> LowerInto<'tcx, ty::subst::GenericArg<'tcx>> + for &chalk_ir::GenericArg> +{ + fn lower_into(self, interner: &RustInterner<'tcx>) -> ty::subst::GenericArg<'tcx> { + match self.data(interner) { + chalk_ir::GenericArgData::Ty(ty) => { + let t: Ty<'tcx> = ty.lower_into(interner); + t.into() + } + chalk_ir::GenericArgData::Lifetime(lifetime) => { + let r: Region<'tcx> = lifetime.lower_into(interner); + r.into() + } + chalk_ir::GenericArgData::Const(c) => { + let c: ty::Const<'tcx> = c.lower_into(interner); + interner.tcx.mk_const(c).into() + } + } + } +} + // We lower into an Option here since there are some predicates which Chalk // doesn't have a representation for yet (as a `WhereClause`), but are so common // that we just are accepting the unsoundness for now. The `Option` will @@ -554,33 +657,27 @@ impl<'tcx> LowerInto<'tcx, Option, ) -> Option>> { - // FIXME(chalk): forall - match self.bound_atom(interner.tcx).skip_binder() { + let (predicate, binders, _named_regions) = + collect_bound_vars(interner, interner.tcx, &self.bound_atom(interner.tcx)); + let value = match predicate { ty::PredicateAtom::Trait(predicate, _) => { - let predicate = ty::Binder::bind(predicate); - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &predicate); - - Some(chalk_ir::Binders::new( - binders, - chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner)), - )) + Some(chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner))) } ty::PredicateAtom::RegionOutlives(predicate) => { - let predicate = ty::Binder::bind(predicate); - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &predicate); - - Some(chalk_ir::Binders::new( - binders, - chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { - a: predicate.0.lower_into(interner), - b: predicate.1.lower_into(interner), - }), - )) + Some(chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { + a: predicate.0.lower_into(interner), + b: predicate.1.lower_into(interner), + })) + } + ty::PredicateAtom::TypeOutlives(predicate) => { + Some(chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { + ty: predicate.0.lower_into(interner), + lifetime: predicate.1.lower_into(interner), + })) + } + ty::PredicateAtom::Projection(predicate) => { + Some(chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner))) } - ty::PredicateAtom::TypeOutlives(_predicate) => None, - ty::PredicateAtom::Projection(_predicate) => None, ty::PredicateAtom::WellFormed(_ty) => None, ty::PredicateAtom::ObjectSafe(..) @@ -588,7 +685,8 @@ impl<'tcx> LowerInto<'tcx, Option bug!("unexpected predicate {}", &self), - } + }; + value.map(|value| chalk_ir::Binders::new(binders, value)) } } @@ -601,26 +699,34 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders chalk_ir::Binders>> { let (predicates, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, &self); + let self_ty = interner.tcx.mk_ty(ty::Bound( + // This is going to be wrapped in a binder + ty::DebruijnIndex::from_usize(1), + ty::BoundTy { var: ty::BoundVar::from_usize(0), kind: ty::BoundTyKind::Anon }, + )); let where_clauses = predicates.into_iter().map(|predicate| match predicate { ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { def_id, substs }) => { chalk_ir::Binders::new( - chalk_ir::VariableKinds::new(interner), + chalk_ir::VariableKinds::empty(interner), chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef { trait_id: chalk_ir::TraitId(def_id), - substitution: substs.lower_into(interner), + substitution: interner + .tcx + .mk_substs_trait(self_ty, substs) + .lower_into(interner), }), ) } ty::ExistentialPredicate::Projection(_predicate) => unimplemented!(), ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new( - chalk_ir::VariableKinds::new(interner), + chalk_ir::VariableKinds::empty(interner), chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef { trait_id: chalk_ir::TraitId(def_id), - substitution: chalk_ir::Substitution::empty(interner), + substitution: interner.tcx.mk_substs_trait(self_ty, &[]).lower_into(interner), }), ), }); - let value = chalk_ir::QuantifiedWhereClauses::from(interner, where_clauses); + let value = chalk_ir::QuantifiedWhereClauses::from_iter(interner, where_clauses); chalk_ir::Binders::new(binders, value) } } @@ -662,7 +768,8 @@ crate fn collect_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>>( .or_else(|| bug!("Skipped bound var index: ty={:?}, parameters={:?}", ty, parameters)); }); - let binders = chalk_ir::VariableKinds::from(interner, parameters.into_iter().map(|(_, v)| v)); + let binders = + chalk_ir::VariableKinds::from_iter(interner, parameters.into_iter().map(|(_, v)| v)); (new_ty, binders, named_parameters) } @@ -773,10 +880,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for NamedBoundVarSubstitutor<'a, 'tcx> { result } - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - t.super_fold_with(self) - } - fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> { match r { ty::ReLateBound(index, br) if *index == self.binder_index => match br { @@ -807,16 +910,18 @@ crate struct ParamsSubstitutor<'tcx> { tcx: TyCtxt<'tcx>, binder_index: ty::DebruijnIndex, list: Vec, + next_ty_placeholder: usize, crate params: rustc_data_structures::fx::FxHashMap, crate named_regions: BTreeMap, } impl<'tcx> ParamsSubstitutor<'tcx> { - crate fn new(tcx: TyCtxt<'tcx>) -> Self { + crate fn new(tcx: TyCtxt<'tcx>, next_ty_placeholder: usize) -> Self { ParamsSubstitutor { tcx, binder_index: ty::INNERMOST, list: vec![], + next_ty_placeholder, params: rustc_data_structures::fx::FxHashMap::default(), named_regions: BTreeMap::default(), } @@ -842,13 +947,13 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> { // first pass to collect placeholders. Then we can insert params after. ty::Placeholder(_) => unimplemented!(), ty::Param(param) => match self.list.iter().position(|r| r == ¶m) { - Some(_idx) => self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType { + Some(idx) => self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType { universe: ty::UniverseIndex::from_usize(0), - name: ty::BoundVar::from_usize(_idx), + name: ty::BoundVar::from_usize(idx), })), None => { self.list.push(param); - let idx = self.list.len() - 1; + let idx = self.list.len() - 1 + self.next_ty_placeholder; self.params.insert(idx, param); self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType { universe: ty::UniverseIndex::from_usize(0), @@ -884,3 +989,83 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> { } } } + +/// Used to collect `Placeholder`s. +crate struct PlaceholdersCollector { + universe_index: ty::UniverseIndex, + crate next_ty_placeholder: usize, + crate next_anon_region_placeholder: u32, +} + +impl PlaceholdersCollector { + crate fn new() -> Self { + PlaceholdersCollector { + universe_index: ty::UniverseIndex::ROOT, + next_ty_placeholder: 0, + next_anon_region_placeholder: 0, + } + } +} + +impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector { + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + match t.kind { + ty::Placeholder(p) if p.universe == self.universe_index => { + self.next_ty_placeholder = self.next_ty_placeholder.max(p.name.as_usize() + 1); + } + + _ => (), + }; + + t.super_visit_with(self) + } + + fn visit_region(&mut self, r: Region<'tcx>) -> bool { + match r { + ty::RePlaceholder(p) if p.universe == self.universe_index => { + if let ty::BoundRegion::BrAnon(anon) = p.name { + self.next_anon_region_placeholder = self.next_anon_region_placeholder.max(anon); + } + } + + _ => (), + }; + + r.super_visit_with(self) + } +} + +/// Used to substitute specific `Regions`s with placeholders. +crate struct RegionsSubstitutor<'tcx> { + tcx: TyCtxt<'tcx>, + restatic_placeholder: ty::Region<'tcx>, + reempty_placeholder: ty::Region<'tcx>, +} + +impl<'tcx> RegionsSubstitutor<'tcx> { + crate fn new( + tcx: TyCtxt<'tcx>, + restatic_placeholder: ty::Region<'tcx>, + reempty_placeholder: ty::Region<'tcx>, + ) -> Self { + RegionsSubstitutor { tcx, restatic_placeholder, reempty_placeholder } + } +} + +impl<'tcx> TypeFolder<'tcx> for RegionsSubstitutor<'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> { + match r { + ty::ReStatic => self.restatic_placeholder, + ty::ReEmpty(ui) => { + assert_eq!(ui.as_usize(), 0); + self.reempty_placeholder + } + + _ => r.super_fold_with(self), + } + } +} diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs index f18b4ca65f6f8..c0d4a5d0e7e5c 100644 --- a/compiler/rustc_traits/src/chalk/mod.rs +++ b/compiler/rustc_traits/src/chalk/mod.rs @@ -15,9 +15,7 @@ use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind}; use rustc_middle::traits::ChalkRustInterner; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::GenericArg; -use rustc_middle::ty::{ - self, Bound, BoundVar, ParamTy, Region, RegionKind, Ty, TyCtxt, TypeFoldable, -}; +use rustc_middle::ty::{self, BoundVar, ParamTy, TyCtxt, TypeFoldable}; use rustc_infer::infer::canonical::{ Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse, @@ -25,7 +23,9 @@ use rustc_infer::infer::canonical::{ use rustc_infer::traits::{self, ChalkCanonicalGoal}; use crate::chalk::db::RustIrDatabase as ChalkRustIrDatabase; -use crate::chalk::lowering::{LowerInto, ParamsSubstitutor}; +use crate::chalk::lowering::{ + LowerInto, ParamsSubstitutor, PlaceholdersCollector, RegionsSubstitutor, +}; use chalk_solve::Solution; @@ -40,16 +40,35 @@ crate fn evaluate_goal<'tcx>( let interner = ChalkRustInterner { tcx }; // Chalk doesn't have a notion of `Params`, so instead we use placeholders. - let mut params_substitutor = ParamsSubstitutor::new(tcx); + let mut placeholders_collector = PlaceholdersCollector::new(); + obligation.visit_with(&mut placeholders_collector); + + let restatic_placeholder = tcx.mk_region(ty::RegionKind::RePlaceholder(ty::Placeholder { + universe: ty::UniverseIndex::ROOT, + name: ty::BoundRegion::BrAnon(placeholders_collector.next_anon_region_placeholder), + })); + let reempty_placeholder = tcx.mk_region(ty::RegionKind::RePlaceholder(ty::Placeholder { + universe: ty::UniverseIndex::ROOT, + name: ty::BoundRegion::BrAnon(placeholders_collector.next_anon_region_placeholder + 1), + })); + + let mut params_substitutor = + ParamsSubstitutor::new(tcx, placeholders_collector.next_ty_placeholder); let obligation = obligation.fold_with(&mut params_substitutor); + // FIXME(chalk): we really should be substituting these back in the solution let _params: FxHashMap = params_substitutor.params; + + let mut regions_substitutor = + RegionsSubstitutor::new(tcx, restatic_placeholder, reempty_placeholder); + let obligation = obligation.fold_with(&mut regions_substitutor); + let max_universe = obligation.max_universe.index(); - let _lowered_goal: chalk_ir::UCanonical< + let lowered_goal: chalk_ir::UCanonical< chalk_ir::InEnvironment>>, > = chalk_ir::UCanonical { canonical: chalk_ir::Canonical { - binders: chalk_ir::CanonicalVarKinds::from( + binders: chalk_ir::CanonicalVarKinds::from_iter( &interner, obligation.variables.iter().map(|v| match v.kind { CanonicalVarKind::PlaceholderTy(_ty) => unimplemented!(), @@ -81,108 +100,20 @@ crate fn evaluate_goal<'tcx>( universes: max_universe + 1, }; - let solver_choice = chalk_solve::SolverChoice::SLG { max_size: 32, expected_answers: None }; - let mut solver = solver_choice.into_solver::>(); - - let db = ChalkRustIrDatabase { tcx, interner }; - let solution = solver.solve(&db, &_lowered_goal); + use chalk_solve::Solver; + let mut solver = chalk_engine::solve::SLGSolver::new(32, None); + let db = ChalkRustIrDatabase { interner, restatic_placeholder, reempty_placeholder }; + let solution = chalk_solve::logging::with_tracing_logs(|| solver.solve(&db, &lowered_goal)); // Ideally, the code to convert *back* to rustc types would live close to // the code to convert *from* rustc types. Right now though, we don't // really need this and so it's really minimal. // Right now, we also treat a `Unique` solution the same as // `Ambig(Definite)`. This really isn't right. - let make_solution = |_subst: chalk_ir::Substitution<_>| { + let make_solution = |subst: chalk_ir::Substitution<_>| { let mut var_values: IndexVec> = IndexVec::new(); - _subst.parameters(&interner).iter().for_each(|p| { - // FIXME(chalk): we should move this elsewhere, since this is - // essentially inverse of lowering a `GenericArg`. - let _data = p.data(&interner); - match _data { - chalk_ir::GenericArgData::Ty(_t) => { - use chalk_ir::TyData; - use rustc_ast as ast; - - let _data = _t.data(&interner); - let kind = match _data { - TyData::Apply(_application_ty) => match _application_ty.name { - chalk_ir::TypeName::Adt(_struct_id) => unimplemented!(), - chalk_ir::TypeName::Scalar(scalar) => match scalar { - chalk_ir::Scalar::Bool => ty::Bool, - chalk_ir::Scalar::Char => ty::Char, - chalk_ir::Scalar::Int(int_ty) => match int_ty { - chalk_ir::IntTy::Isize => ty::Int(ast::IntTy::Isize), - chalk_ir::IntTy::I8 => ty::Int(ast::IntTy::I8), - chalk_ir::IntTy::I16 => ty::Int(ast::IntTy::I16), - chalk_ir::IntTy::I32 => ty::Int(ast::IntTy::I32), - chalk_ir::IntTy::I64 => ty::Int(ast::IntTy::I64), - chalk_ir::IntTy::I128 => ty::Int(ast::IntTy::I128), - }, - chalk_ir::Scalar::Uint(int_ty) => match int_ty { - chalk_ir::UintTy::Usize => ty::Uint(ast::UintTy::Usize), - chalk_ir::UintTy::U8 => ty::Uint(ast::UintTy::U8), - chalk_ir::UintTy::U16 => ty::Uint(ast::UintTy::U16), - chalk_ir::UintTy::U32 => ty::Uint(ast::UintTy::U32), - chalk_ir::UintTy::U64 => ty::Uint(ast::UintTy::U64), - chalk_ir::UintTy::U128 => ty::Uint(ast::UintTy::U128), - }, - chalk_ir::Scalar::Float(float_ty) => match float_ty { - chalk_ir::FloatTy::F32 => ty::Float(ast::FloatTy::F32), - chalk_ir::FloatTy::F64 => ty::Float(ast::FloatTy::F64), - }, - }, - chalk_ir::TypeName::Array => unimplemented!(), - chalk_ir::TypeName::FnDef(_) => unimplemented!(), - chalk_ir::TypeName::Closure(_) => unimplemented!(), - chalk_ir::TypeName::Never => unimplemented!(), - chalk_ir::TypeName::Tuple(_size) => unimplemented!(), - chalk_ir::TypeName::Slice => unimplemented!(), - chalk_ir::TypeName::Raw(_) => unimplemented!(), - chalk_ir::TypeName::Ref(_) => unimplemented!(), - chalk_ir::TypeName::Str => unimplemented!(), - chalk_ir::TypeName::OpaqueType(_ty) => unimplemented!(), - chalk_ir::TypeName::AssociatedType(_assoc_ty) => unimplemented!(), - chalk_ir::TypeName::Error => unimplemented!(), - }, - TyData::Placeholder(_placeholder) => { - unimplemented!(); - } - TyData::Alias(_alias_ty) => unimplemented!(), - TyData::Function(_quantified_ty) => unimplemented!(), - TyData::BoundVar(_bound) => Bound( - ty::DebruijnIndex::from_usize(_bound.debruijn.depth() as usize), - ty::BoundTy { - var: ty::BoundVar::from_usize(_bound.index), - kind: ty::BoundTyKind::Anon, - }, - ), - TyData::InferenceVar(_, _) => unimplemented!(), - TyData::Dyn(_) => unimplemented!(), - }; - let _ty: Ty<'_> = tcx.mk_ty(kind); - let _arg: GenericArg<'_> = _ty.into(); - var_values.push(_arg); - } - chalk_ir::GenericArgData::Lifetime(_l) => { - let _data = _l.data(&interner); - let _lifetime: Region<'_> = match _data { - chalk_ir::LifetimeData::BoundVar(_var) => { - tcx.mk_region(RegionKind::ReLateBound( - rustc_middle::ty::DebruijnIndex::from_usize( - _var.debruijn.depth() as usize - ), - rustc_middle::ty::BoundRegion::BrAnon(_var.index as u32), - )) - } - chalk_ir::LifetimeData::InferenceVar(_var) => unimplemented!(), - chalk_ir::LifetimeData::Placeholder(_index) => unimplemented!(), - chalk_ir::LifetimeData::Phantom(_, _) => unimplemented!(), - }; - let _arg: GenericArg<'_> = _lifetime.into(); - var_values.push(_arg); - } - chalk_ir::GenericArgData::Const(_) => unimplemented!(), - } + subst.as_slice(&interner).iter().for_each(|p| { + var_values.push(p.lower_into(&interner)); }); let sol = Canonical { max_universe: ty::UniverseIndex::from_usize(0), @@ -194,17 +125,17 @@ crate fn evaluate_goal<'tcx>( value: (), }, }; - &*tcx.arena.alloc(sol) + tcx.arena.alloc(sol) }; solution .map(|s| match s { - Solution::Unique(_subst) => { + Solution::Unique(subst) => { // FIXME(chalk): handle constraints - make_solution(_subst.value.subst) + make_solution(subst.value.subst) } - Solution::Ambig(_guidance) => { - match _guidance { - chalk_solve::Guidance::Definite(_subst) => make_solution(_subst.value), + Solution::Ambig(guidance) => { + match guidance { + chalk_solve::Guidance::Definite(subst) => make_solution(subst.value), chalk_solve::Guidance::Suggested(_) => unimplemented!(), chalk_solve::Guidance::Unknown => { // chalk_fulfill doesn't use the var_values here, so diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs index cdbed28f754b1..aed2af20e5271 100644 --- a/compiler/rustc_typeck/src/check/place_op.rs +++ b/compiler/rustc_typeck/src/check/place_op.rs @@ -193,7 +193,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Convert auto-derefs, indices, etc of an expression from `Deref` and `Index` /// into `DerefMut` and `IndexMut` respectively. /// - /// This is a second pass of typechecking derefs/indices. We need this we do not + /// This is a second pass of typechecking derefs/indices. We need this because we do not /// always know whether a place needs to be mutable or not in the first pass. /// This happens whether there is an implicit mutable reborrow, e.g. when the type /// is used as the receiver of a method call. @@ -211,13 +211,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs); // Fix up autoderefs and derefs. + let mut inside_union = false; for (i, &expr) in exprs.iter().rev().enumerate() { debug!("convert_place_derefs_to_mutable: i={} expr={:?}", i, expr); + let mut source = self.node_ty(expr.hir_id); + if matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::UnDeref, _)) { + // Clear previous flag; after a pointer indirection it does not apply any more. + inside_union = false; + } + if source.ty_adt_def().map_or(false, |adt| adt.is_union()) { + inside_union = true; + } // Fix up the autoderefs. Autorefs can only occur immediately preceding // overloaded place ops, and will be fixed by them in order to get // the correct region. - let mut source = self.node_ty(expr.hir_id); // Do not mutate adjustments in place, but rather take them, // and replace them after mutating them, to avoid having the // typeck results borrowed during (`deref_mut`) method resolution. @@ -236,6 +244,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() { *deref = OverloadedDeref { region, mutbl }; } + // If this is a union field, also throw an error for `DerefMut` of `ManuallyDrop` (see RFC 2514). + // This helps avoid accidental drops. + if inside_union + && source.ty_adt_def().map_or(false, |adt| adt.is_manually_drop()) + { + let mut err = self.tcx.sess.struct_span_err( + expr.span, + "not automatically applying `DerefMut` on `ManuallyDrop` union field", + ); + err.help( + "writing to this reference calls the destructor for the old value", + ); + err.help("add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor"); + err.emit(); + } } } source = adjustment.target; diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index f8729c33c6713..92f02fb60168b 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -5,7 +5,6 @@ use core::hash::{Hash, Hasher}; use core::iter::{FromIterator, FusedIterator, Peekable}; use core::marker::PhantomData; use core::mem::{self, ManuallyDrop}; -use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{Index, RangeBounds}; use core::ptr; @@ -408,8 +407,8 @@ impl fmt::Debug for Range<'_, K, V> { /// [`range_mut`]: BTreeMap::range_mut #[stable(feature = "btree_range", since = "1.17.0")] pub struct RangeMut<'a, K: 'a, V: 'a> { - front: Option, K, V, marker::Leaf>, marker::Edge>>, - back: Option, K, V, marker::Leaf>, marker::Edge>>, + front: Option, K, V, marker::Leaf>, marker::Edge>>, + back: Option, K, V, marker::Leaf>, marker::Edge>>, // Be invariant in `K` and `V` _marker: PhantomData<&'a mut (K, V)>, @@ -999,7 +998,7 @@ impl BTreeMap { R: RangeBounds, { if let Some(root) = &self.root { - let (f, b) = range_search(root.node_as_ref(), range); + let (f, b) = root.node_as_ref().range_search(range); Range { front: Some(f), back: Some(b) } } else { @@ -1045,7 +1044,7 @@ impl BTreeMap { R: RangeBounds, { if let Some(root) = &mut self.root { - let (f, b) = range_search(root.node_as_mut(), range); + let (f, b) = root.node_as_valmut().range_search(range); RangeMut { front: Some(f), back: Some(b), _marker: PhantomData } } else { @@ -1478,7 +1477,7 @@ impl IntoIterator for BTreeMap { fn into_iter(self) -> IntoIter { let mut me = ManuallyDrop::new(self); if let Some(root) = me.root.take() { - let (f, b) = full_range_search(root.into_ref()); + let (f, b) = root.into_ref().full_range(); IntoIter { front: Some(f), back: Some(b), length: me.length } } else { @@ -1942,7 +1941,7 @@ impl<'a, K, V> RangeMut<'a, K, V> { self.front == self.back } - unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) { + unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) { unsafe { unwrap_unchecked(self.front.as_mut()).next_unchecked() } } } @@ -1963,7 +1962,7 @@ impl<'a, K, V> DoubleEndedIterator for RangeMut<'a, K, V> { impl FusedIterator for RangeMut<'_, K, V> {} impl<'a, K, V> RangeMut<'a, K, V> { - unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) { + unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) { unsafe { unwrap_unchecked(self.back.as_mut()).next_back_unchecked() } } } @@ -2073,119 +2072,6 @@ where } } -/// Finds the leaf edges delimiting a specified range in or underneath a node. -fn range_search>( - root: NodeRef, - range: R, -) -> ( - Handle, marker::Edge>, - Handle, marker::Edge>, -) -where - Q: Ord, - K: Borrow, -{ - match (range.start_bound(), range.end_bound()) { - (Excluded(s), Excluded(e)) if s == e => { - panic!("range start and end are equal and excluded in BTreeMap") - } - (Included(s) | Excluded(s), Included(e) | Excluded(e)) if s > e => { - panic!("range start is greater than range end in BTreeMap") - } - _ => {} - }; - - // We duplicate the root NodeRef here -- we will never access it in a way - // that overlaps references obtained from the root. - let mut min_node = unsafe { ptr::read(&root) }; - let mut max_node = root; - let mut min_found = false; - let mut max_found = false; - - loop { - let front = match (min_found, range.start_bound()) { - (false, Included(key)) => match search::search_node(min_node, key) { - Found(kv) => { - min_found = true; - kv.left_edge() - } - GoDown(edge) => edge, - }, - (false, Excluded(key)) => match search::search_node(min_node, key) { - Found(kv) => { - min_found = true; - kv.right_edge() - } - GoDown(edge) => edge, - }, - (true, Included(_)) => min_node.last_edge(), - (true, Excluded(_)) => min_node.first_edge(), - (_, Unbounded) => min_node.first_edge(), - }; - - let back = match (max_found, range.end_bound()) { - (false, Included(key)) => match search::search_node(max_node, key) { - Found(kv) => { - max_found = true; - kv.right_edge() - } - GoDown(edge) => edge, - }, - (false, Excluded(key)) => match search::search_node(max_node, key) { - Found(kv) => { - max_found = true; - kv.left_edge() - } - GoDown(edge) => edge, - }, - (true, Included(_)) => max_node.first_edge(), - (true, Excluded(_)) => max_node.last_edge(), - (_, Unbounded) => max_node.last_edge(), - }; - - if front.partial_cmp(&back) == Some(Ordering::Greater) { - panic!("Ord is ill-defined in BTreeMap range"); - } - match (front.force(), back.force()) { - (Leaf(f), Leaf(b)) => { - return (f, b); - } - (Internal(min_int), Internal(max_int)) => { - min_node = min_int.descend(); - max_node = max_int.descend(); - } - _ => unreachable!("BTreeMap has different depths"), - }; - } -} - -/// Equivalent to `range_search(k, v, ..)` without the `Ord` bound. -fn full_range_search( - root: NodeRef, -) -> ( - Handle, marker::Edge>, - Handle, marker::Edge>, -) { - // We duplicate the root NodeRef here -- we will never access it in a way - // that overlaps references obtained from the root. - let mut min_node = unsafe { ptr::read(&root) }; - let mut max_node = root; - loop { - let front = min_node.first_edge(); - let back = max_node.last_edge(); - match (front.force(), back.force()) { - (Leaf(f), Leaf(b)) => { - return (f, b); - } - (Internal(min_int), Internal(max_int)) => { - min_node = min_int.descend(); - max_node = max_int.descend(); - } - _ => unreachable!("BTreeMap has different depths"), - }; - } -} - impl BTreeMap { /// Gets an iterator over the entries of the map, sorted by key. /// @@ -2211,7 +2097,7 @@ impl BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter<'_, K, V> { if let Some(root) = &self.root { - let (f, b) = full_range_search(root.node_as_ref()); + let (f, b) = root.node_as_ref().full_range(); Iter { range: Range { front: Some(f), back: Some(b) }, length: self.length } } else { @@ -2243,7 +2129,7 @@ impl BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { if let Some(root) = &mut self.root { - let (f, b) = full_range_search(root.node_as_mut()); + let (f, b) = root.node_as_valmut().full_range(); IterMut { range: RangeMut { front: Some(f), back: Some(b), _marker: PhantomData }, @@ -2826,7 +2712,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::LeafOrInter if stole_from_left && at_leaf { // SAFETY: This is safe since we just added an element to our node. unsafe { - pos.next_unchecked(); + pos.move_next_unchecked(); } } break; diff --git a/library/alloc/src/collections/btree/navigate.rs b/library/alloc/src/collections/btree/navigate.rs index b7b66ac7ceccd..376060b3143de 100644 --- a/library/alloc/src/collections/btree/navigate.rs +++ b/library/alloc/src/collections/btree/navigate.rs @@ -1,10 +1,210 @@ +use core::borrow::Borrow; +use core::cmp::Ordering; use core::intrinsics; use core::mem; +use core::ops::Bound::{Excluded, Included, Unbounded}; +use core::ops::RangeBounds; use core::ptr; use super::node::{marker, ForceResult::*, Handle, NodeRef}; +use super::search::{self, SearchResult}; use super::unwrap_unchecked; +/// Finds the leaf edges delimiting a specified range in or underneath a node. +fn range_search( + root1: NodeRef, + root2: NodeRef, + range: R, +) -> ( + Handle, marker::Edge>, + Handle, marker::Edge>, +) +where + Q: ?Sized + Ord, + K: Borrow, + R: RangeBounds, +{ + match (range.start_bound(), range.end_bound()) { + (Excluded(s), Excluded(e)) if s == e => { + panic!("range start and end are equal and excluded in BTreeMap") + } + (Included(s) | Excluded(s), Included(e) | Excluded(e)) if s > e => { + panic!("range start is greater than range end in BTreeMap") + } + _ => {} + }; + + let mut min_node = root1; + let mut max_node = root2; + let mut min_found = false; + let mut max_found = false; + + loop { + let front = match (min_found, range.start_bound()) { + (false, Included(key)) => match search::search_node(min_node, key) { + SearchResult::Found(kv) => { + min_found = true; + kv.left_edge() + } + SearchResult::GoDown(edge) => edge, + }, + (false, Excluded(key)) => match search::search_node(min_node, key) { + SearchResult::Found(kv) => { + min_found = true; + kv.right_edge() + } + SearchResult::GoDown(edge) => edge, + }, + (true, Included(_)) => min_node.last_edge(), + (true, Excluded(_)) => min_node.first_edge(), + (_, Unbounded) => min_node.first_edge(), + }; + + let back = match (max_found, range.end_bound()) { + (false, Included(key)) => match search::search_node(max_node, key) { + SearchResult::Found(kv) => { + max_found = true; + kv.right_edge() + } + SearchResult::GoDown(edge) => edge, + }, + (false, Excluded(key)) => match search::search_node(max_node, key) { + SearchResult::Found(kv) => { + max_found = true; + kv.left_edge() + } + SearchResult::GoDown(edge) => edge, + }, + (true, Included(_)) => max_node.first_edge(), + (true, Excluded(_)) => max_node.last_edge(), + (_, Unbounded) => max_node.last_edge(), + }; + + if front.partial_cmp(&back) == Some(Ordering::Greater) { + panic!("Ord is ill-defined in BTreeMap range"); + } + match (front.force(), back.force()) { + (Leaf(f), Leaf(b)) => { + return (f, b); + } + (Internal(min_int), Internal(max_int)) => { + min_node = min_int.descend(); + max_node = max_int.descend(); + } + _ => unreachable!("BTreeMap has different depths"), + }; + } +} + +/// Equivalent to `range_search(k, v, ..)` but without the `Ord` bound. +fn full_range( + root1: NodeRef, + root2: NodeRef, +) -> ( + Handle, marker::Edge>, + Handle, marker::Edge>, +) { + let mut min_node = root1; + let mut max_node = root2; + loop { + let front = min_node.first_edge(); + let back = max_node.last_edge(); + match (front.force(), back.force()) { + (Leaf(f), Leaf(b)) => { + return (f, b); + } + (Internal(min_int), Internal(max_int)) => { + min_node = min_int.descend(); + max_node = max_int.descend(); + } + _ => unreachable!("BTreeMap has different depths"), + }; + } +} + +impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { + /// Creates a pair of leaf edges delimiting a specified range in or underneath a node. + pub fn range_search( + self, + range: R, + ) -> ( + Handle, K, V, marker::Leaf>, marker::Edge>, + Handle, K, V, marker::Leaf>, marker::Edge>, + ) + where + Q: ?Sized + Ord, + K: Borrow, + R: RangeBounds, + { + range_search(self, self, range) + } + + /// Returns (self.first_leaf_edge(), self.last_leaf_edge()), but more efficiently. + pub fn full_range( + self, + ) -> ( + Handle, K, V, marker::Leaf>, marker::Edge>, + Handle, K, V, marker::Leaf>, marker::Edge>, + ) { + full_range(self, self) + } +} + +impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { + /// Splits a unique reference into a pair of leaf edges delimiting a specified range. + /// The result are non-unique references allowing (some) mutation, which must be used + /// carefully. + pub fn range_search( + self, + range: R, + ) -> ( + Handle, K, V, marker::Leaf>, marker::Edge>, + Handle, K, V, marker::Leaf>, marker::Edge>, + ) + where + Q: ?Sized + Ord, + K: Borrow, + R: RangeBounds, + { + // We duplicate the root NodeRef here -- we will never visit the same KV + // twice, and never end up with overlapping value references. + let self2 = unsafe { ptr::read(&self) }; + range_search(self, self2, range) + } + + /// Splits a unique reference into a pair of leaf edges delimiting the full range of the tree. + /// The results are non-unique references allowing mutation (of values only), so must be used + /// with care. + pub fn full_range( + self, + ) -> ( + Handle, K, V, marker::Leaf>, marker::Edge>, + Handle, K, V, marker::Leaf>, marker::Edge>, + ) { + // We duplicate the root NodeRef here -- we will never visit the same KV + // twice, and never end up with overlapping value references. + let self2 = unsafe { ptr::read(&self) }; + full_range(self, self2) + } +} + +impl NodeRef { + /// Splits a unique reference into a pair of leaf edges delimiting the full range of the tree. + /// The results are non-unique references allowing massively destructive mutation, so must be + /// used with the utmost care. + pub fn full_range( + self, + ) -> ( + Handle, marker::Edge>, + Handle, marker::Edge>, + ) { + // We duplicate the root NodeRef here -- we will never access it in a way + // that overlaps references obtained from the root. + let self2 = unsafe { ptr::read(&self) }; + full_range(self, self2) + } +} + impl Handle, marker::Edge> { /// Given a leaf edge handle, returns [`Result::Ok`] with a handle to the neighboring KV /// on the right side, which is either in the same leaf node or in an ancestor node. @@ -75,12 +275,13 @@ impl Handle, marke macro_rules! def_next_kv_uncheched_dealloc { { unsafe fn $name:ident : $adjacent_kv:ident } => { /// Given a leaf edge handle into an owned tree, returns a handle to the next KV, - /// while deallocating any node left behind. - /// Unsafe for two reasons: - /// - The caller must ensure that the leaf edge is not the last one in the tree. - /// - The node pointed at by the given handle, and its ancestors, may be deallocated, - /// while the reference to those nodes in the surviving ancestors is left dangling; - /// thus using the returned handle to navigate further is dangerous. + /// while deallocating any node left behind yet leaving the corresponding edge + /// in its parent node dangling. + /// + /// # Safety + /// - The leaf edge must not be the last one in the direction travelled. + /// - The node carrying the next KV returned must not have been deallocated by a + /// previous call on any handle obtained for this tree. unsafe fn $name ( leaf_edge: Handle, marker::Edge>, ) -> Handle, marker::KV> { @@ -103,6 +304,15 @@ macro_rules! def_next_kv_uncheched_dealloc { def_next_kv_uncheched_dealloc! {unsafe fn next_kv_unchecked_dealloc: right_kv} def_next_kv_uncheched_dealloc! {unsafe fn next_back_kv_unchecked_dealloc: left_kv} +/// This replaces the value behind the `v` unique reference by calling the +/// relevant function. +/// +/// If a panic occurs in the `change` closure, the entire process will be aborted. +#[inline] +fn take_mut(v: &mut T, change: impl FnOnce(T) -> T) { + replace(v, |value| (change(value), ())) +} + /// This replaces the value behind the `v` unique reference by calling the /// relevant function, and returns a result obtained along the way. /// @@ -128,7 +338,9 @@ fn replace(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R { impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { /// Moves the leaf edge handle to the next leaf edge and returns references to the /// key and value in between. - /// Unsafe because the caller must ensure that the leaf edge is not the last one in the tree. + /// + /// # Safety + /// There must be another KV in the direction travelled. pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) { replace(self, |leaf_edge| { let kv = leaf_edge.next_kv(); @@ -139,7 +351,9 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Ed /// Moves the leaf edge handle to the previous leaf edge and returns references to the /// key and value in between. - /// Unsafe because the caller must ensure that the leaf edge is not the first one in the tree. + /// + /// # Safety + /// There must be another KV in the direction travelled. pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) { replace(self, |leaf_edge| { let kv = leaf_edge.next_back_kv(); @@ -149,53 +363,69 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Ed } } -impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { +impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { /// Moves the leaf edge handle to the next leaf edge and returns references to the /// key and value in between. - /// Unsafe for two reasons: - /// - The caller must ensure that the leaf edge is not the last one in the tree. - /// - Using the updated handle may well invalidate the returned references. - pub unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) { + /// The returned references might be invalidated when the updated handle is used again. + /// + /// # Safety + /// There must be another KV in the direction travelled. + pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) { let kv = replace(self, |leaf_edge| { let kv = leaf_edge.next_kv(); let kv = unsafe { unwrap_unchecked(kv.ok()) }; (unsafe { ptr::read(&kv) }.next_leaf_edge(), kv) }); // Doing the descend (and perhaps another move) invalidates the references - // returned by `into_kv_mut`, so we have to do this last. - kv.into_kv_mut() + // returned by `into_kv_valmut`, so we have to do this last. + kv.into_kv_valmut() } /// Moves the leaf edge handle to the previous leaf and returns references to the /// key and value in between. - /// Unsafe for two reasons: - /// - The caller must ensure that the leaf edge is not the first one in the tree. - /// - Using the updated handle may well invalidate the returned references. - pub unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) { + /// The returned references might be invalidated when the updated handle is used again. + /// + /// # Safety + /// There must be another KV in the direction travelled. + pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) { let kv = replace(self, |leaf_edge| { let kv = leaf_edge.next_back_kv(); let kv = unsafe { unwrap_unchecked(kv.ok()) }; (unsafe { ptr::read(&kv) }.next_back_leaf_edge(), kv) }); // Doing the descend (and perhaps another move) invalidates the references - // returned by `into_kv_mut`, so we have to do this last. - kv.into_kv_mut() + // returned by `into_kv_valmut`, so we have to do this last. + kv.into_kv_valmut() + } +} + +impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { + /// Moves the leaf edge handle to the next leaf edge. + /// + /// # Safety + /// There must be another KV in the direction travelled. + pub unsafe fn move_next_unchecked(&mut self) { + take_mut(self, |leaf_edge| { + let kv = leaf_edge.next_kv(); + let kv = unsafe { unwrap_unchecked(kv.ok()) }; + kv.next_leaf_edge() + }) } } impl Handle, marker::Edge> { /// Moves the leaf edge handle to the next leaf edge and returns the key and value - /// in between, while deallocating any node left behind. - /// Unsafe for two reasons: - /// - The caller must ensure that the leaf edge is not the last one in the tree - /// and is not a handle previously resulting from counterpart `next_back_unchecked`. - /// - Further use of the updated leaf edge handle is very dangerous. In particular, - /// if the leaf edge is the last edge of a node, that node and possibly ancestors - /// will be deallocated, while the reference to those nodes in the surviving ancestor - /// is left dangling. - /// The only safe way to proceed with the updated handle is to compare it, drop it, - /// call this method again subject to both preconditions listed in the first point, - /// or call counterpart `next_back_unchecked` subject to its preconditions. + /// in between, deallocating any node left behind while leaving the corresponding + /// edge in its parent node dangling. + /// + /// # Safety + /// - There must be another KV in the direction travelled. + /// - That KV was not previously returned by counterpart `next_back_unchecked` + /// on any copy of the handles being used to traverse the tree. + /// + /// The only safe way to proceed with the updated handle is to compare it, drop it, + /// call this method again subject to its safety conditions, or call counterpart + /// `next_back_unchecked` subject to its safety conditions. pub unsafe fn next_unchecked(&mut self) -> (K, V) { replace(self, |leaf_edge| { let kv = unsafe { next_kv_unchecked_dealloc(leaf_edge) }; @@ -205,18 +435,18 @@ impl Handle, marker::Edge> { }) } - /// Moves the leaf edge handle to the previous leaf edge and returns the key - /// and value in between, while deallocating any node left behind. - /// Unsafe for two reasons: - /// - The caller must ensure that the leaf edge is not the first one in the tree - /// and is not a handle previously resulting from counterpart `next_unchecked`. - /// - Further use of the updated leaf edge handle is very dangerous. In particular, - /// if the leaf edge is the first edge of a node, that node and possibly ancestors - /// will be deallocated, while the reference to those nodes in the surviving ancestor - /// is left dangling. - /// The only safe way to proceed with the updated handle is to compare it, drop it, - /// call this method again subject to both preconditions listed in the first point, - /// or call counterpart `next_unchecked` subject to its preconditions. + /// Moves the leaf edge handle to the previous leaf edge and returns the key and value + /// in between, deallocating any node left behind while leaving the corresponding + /// edge in its parent node dangling. + /// + /// # Safety + /// - There must be another KV in the direction travelled. + /// - That leaf edge was not previously returned by counterpart `next_unchecked` + /// on any copy of the handles being used to traverse the tree. + /// + /// The only safe way to proceed with the updated handle is to compare it, drop it, + /// call this method again subject to its safety conditions, or call counterpart + /// `next_unchecked` subject to its safety conditions. pub unsafe fn next_back_unchecked(&mut self) -> (K, V) { replace(self, |leaf_edge| { let kv = unsafe { next_back_kv_unchecked_dealloc(leaf_edge) }; diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index acc2ae73572ba..772bdf357de78 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -186,6 +186,15 @@ impl Root { } } + pub fn node_as_valmut(&mut self) -> NodeRef, K, V, marker::LeafOrInternal> { + NodeRef { + height: self.height, + node: self.node.as_ptr(), + root: ptr::null(), + _marker: PhantomData, + } + } + pub fn into_ref(self) -> NodeRef { NodeRef { height: self.height, @@ -253,9 +262,12 @@ impl Root { /// A reference to a node. /// /// This type has a number of parameters that controls how it acts: -/// - `BorrowType`: This can be `Immut<'a>` or `Mut<'a>` for some `'a` or `Owned`. +/// - `BorrowType`: This can be `Immut<'a>`, `Mut<'a>` or `ValMut<'a>' for some `'a` +/// or `Owned`. /// When this is `Immut<'a>`, the `NodeRef` acts roughly like `&'a Node`, /// when this is `Mut<'a>`, the `NodeRef` acts roughly like `&'a mut Node`, +/// when this is `ValMut<'a>`, the `NodeRef` acts as immutable with respect +/// to keys and tree structure, but allows mutable references to values, /// and when this is `Owned`, the `NodeRef` acts roughly like `Box`. /// - `K` and `V`: These control what types of things are stored in the nodes. /// - `Type`: This can be `Leaf`, `Internal`, or `LeafOrInternal`. When this is @@ -282,6 +294,7 @@ unsafe impl Sync for NodeRef Send for NodeRef, K, V, Type> {} unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef, K, V, Type> {} +unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef, K, V, Type> {} unsafe impl Send for NodeRef {} impl NodeRef { @@ -515,6 +528,22 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { } } +impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { + /// Same as the marker::Mut method, but far more dangerous because ValMut-based iterators: + /// - have front and back handles often refering to the same node, so `self` is not unique; + /// - hand out mutable references to parts of these slices to the public. + fn into_slices_mut(self) -> (&'a [K], &'a mut [V]) { + let len = self.len(); + let leaf = self.node.as_ptr(); + // SAFETY: The keys and values of a node must always be initialized up to length. + let keys = unsafe { slice::from_raw_parts(MaybeUninit::first_ptr(&(*leaf).keys), len) }; + let vals = unsafe { + slice::from_raw_parts_mut(MaybeUninit::first_ptr_mut(&mut (*leaf).vals), len) + }; + (keys, vals) + } +} + impl<'a, K, V> NodeRef, K, V, marker::Leaf> { /// Adds a key/value pair to the end of the node. pub fn push(&mut self, key: K, val: V) { @@ -1053,11 +1082,13 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType> let vals = self.node.into_val_slice_mut(); unsafe { vals.get_unchecked_mut(self.idx) } } +} - pub fn into_kv_mut(self) -> (&'a mut K, &'a mut V) { +impl<'a, K, V, NodeType> Handle, K, V, NodeType>, marker::KV> { + pub fn into_kv_valmut(self) -> (&'a K, &'a mut V) { unsafe { let (keys, vals) = self.node.into_slices_mut(); - (keys.get_unchecked_mut(self.idx), vals.get_unchecked_mut(self.idx)) + (keys.get_unchecked(self.idx), vals.get_unchecked_mut(self.idx)) } } } @@ -1558,6 +1589,7 @@ pub mod marker { pub enum Owned {} pub struct Immut<'a>(PhantomData<&'a ()>); pub struct Mut<'a>(PhantomData<&'a mut ()>); + pub struct ValMut<'a>(PhantomData<&'a mut ()>); pub enum KV {} pub enum Edge {} diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 2f0a374015af6..a9b293856e57b 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -325,6 +325,50 @@ impl Rc { ) } + /// Constructs a new `Rc` using a weak reference to itself. Attempting + /// to upgrade the weak reference before this function returns will result + /// in a `None` value. However, the weak reference may be cloned freely and + /// stored for use at a later time. + #[unstable(feature = "arc_new_cyclic", issue = "75861")] + pub fn new_cyclic(data_fn: impl FnOnce(&Weak) -> T) -> Rc { + // Construct the inner in the "uninitialized" state with a single + // weak reference. + let uninit_ptr: NonNull<_> = Box::leak(box RcBox { + strong: Cell::new(0), + weak: Cell::new(1), + value: mem::MaybeUninit::::uninit(), + }) + .into(); + + let init_ptr: NonNull> = uninit_ptr.cast(); + + let weak = Weak { ptr: init_ptr }; + + // It's important we don't give up ownership of the weak pointer, or + // else the memory might be freed by the time `data_fn` returns. If + // we really wanted to pass ownership, we could create an additional + // weak pointer for ourselves, but this would result in additional + // updates to the weak reference count which might not be necessary + // otherwise. + let data = data_fn(&weak); + + unsafe { + let inner = init_ptr.as_ptr(); + ptr::write(&raw mut (*inner).value, data); + + let prev_value = (*inner).strong.get(); + debug_assert_eq!(prev_value, 0, "No prior strong references should exist"); + (*inner).strong.set(1); + } + + let strong = Rc::from_inner(init_ptr); + + // Strong references should collectively own a shared weak reference, + // so don't run the destructor for our old weak reference. + mem::forget(weak); + strong + } + /// Constructs a new `Rc` with uninitialized contents. /// /// # Examples diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs index e88385faf4fd4..fed48a59f809e 100644 --- a/library/alloc/src/rc/tests.rs +++ b/library/alloc/src/rc/tests.rs @@ -434,3 +434,69 @@ fn test_array_from_slice() { let a: Result, _> = r.clone().try_into(); assert!(a.is_err()); } + +#[test] +fn test_rc_cyclic_with_zero_refs() { + struct ZeroRefs { + inner: Weak, + } + + let zero_refs = Rc::new_cyclic(|inner| { + assert_eq!(inner.strong_count(), 0); + assert!(inner.upgrade().is_none()); + ZeroRefs { inner: Weak::new() } + }); + + assert_eq!(Rc::strong_count(&zero_refs), 1); + assert_eq!(Rc::weak_count(&zero_refs), 0); + assert_eq!(zero_refs.inner.strong_count(), 0); + assert_eq!(zero_refs.inner.weak_count(), 0); +} + +#[test] +fn test_rc_cyclic_with_one_ref() { + struct OneRef { + inner: Weak, + } + + let one_ref = Rc::new_cyclic(|inner| { + assert_eq!(inner.strong_count(), 0); + assert!(inner.upgrade().is_none()); + OneRef { inner: inner.clone() } + }); + + assert_eq!(Rc::strong_count(&one_ref), 1); + assert_eq!(Rc::weak_count(&one_ref), 1); + + let one_ref2 = Weak::upgrade(&one_ref.inner).unwrap(); + assert!(Rc::ptr_eq(&one_ref, &one_ref2)); + + assert_eq!(one_ref.inner.strong_count(), 2); + assert_eq!(one_ref.inner.weak_count(), 1); +} + +#[test] +fn test_rc_cyclic_with_two_ref() { + struct TwoRefs { + inner: Weak, + inner1: Weak, + } + + let two_refs = Rc::new_cyclic(|inner| { + assert_eq!(inner.strong_count(), 0); + assert!(inner.upgrade().is_none()); + TwoRefs { inner: inner.clone(), inner1: inner.clone() } + }); + + assert_eq!(Rc::strong_count(&two_refs), 1); + assert_eq!(Rc::weak_count(&two_refs), 2); + + let two_ref3 = Weak::upgrade(&two_refs.inner).unwrap(); + assert!(Rc::ptr_eq(&two_refs, &two_ref3)); + + let two_ref2 = Weak::upgrade(&two_refs.inner1).unwrap(); + assert!(Rc::ptr_eq(&two_refs, &two_ref2)); + + assert_eq!(Rc::strong_count(&two_refs), 3); + assert_eq!(Rc::weak_count(&two_refs), 2); +} diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 6a4fc8e396240..011ea32d0cfc2 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -159,7 +159,7 @@ use crate::raw_vec::RawVec; /// # Slicing /// /// A `Vec` can be mutable. Slices, on the other hand, are read-only objects. -/// To get a slice, use `&`. Example: +/// To get a [slice], use [`&`]. Example: /// /// ``` /// fn read_slice(slice: &[usize]) { @@ -287,6 +287,8 @@ use crate::raw_vec::RawVec; /// [`insert`]: Vec::insert /// [`reserve`]: Vec::reserve /// [owned slice]: Box +/// [slice]: ../../std/primitive.slice.html +/// [`&`]: ../../std/primitive.reference.html #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")] pub struct Vec { diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 8e66c8a22cec5..523c727a69096 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -74,6 +74,42 @@ fn test_zst_capacity() { assert_eq!(Vec::<()>::new().capacity(), usize::MAX); } +#[test] +fn test_indexing() { + let v: Vec = vec![10, 20]; + assert_eq!(v[0], 10); + assert_eq!(v[1], 20); + let mut x: usize = 0; + assert_eq!(v[x], 10); + assert_eq!(v[x + 1], 20); + x = x + 1; + assert_eq!(v[x], 20); + assert_eq!(v[x - 1], 10); +} + +#[test] +fn test_debug_fmt() { + let vec1: Vec = vec![]; + assert_eq!("[]", format!("{:?}", vec1)); + + let vec2 = vec![0, 1]; + assert_eq!("[0, 1]", format!("{:?}", vec2)); + + let slice: &[isize] = &[4, 5]; + assert_eq!("[4, 5]", format!("{:?}", slice)); +} + +#[test] +fn test_push() { + let mut v = vec![]; + v.push(1); + assert_eq!(v, [1]); + v.push(2); + assert_eq!(v, [1, 2]); + v.push(3); + assert_eq!(v, [1, 2, 3]); +} + #[test] fn test_extend() { let mut v = Vec::new(); @@ -119,6 +155,18 @@ fn test_extend() { assert_eq!(count_x, 1); } +#[test] +fn test_extend_from_slice() { + let a: Vec = vec![1, 2, 3, 4, 5]; + let b: Vec = vec![6, 7, 8, 9, 0]; + + let mut v: Vec = a; + + v.extend_from_slice(&b); + + assert_eq!(v, [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); +} + #[test] fn test_extend_ref() { let mut v = vec![1, 2]; @@ -134,6 +182,14 @@ fn test_extend_ref() { assert_eq!(v, [1, 2, 3, 4, 5, 6, 7]); } +#[test] +fn test_slice_from_ref() { + let values = vec![1, 2, 3, 4, 5]; + let slice = &values[1..3]; + + assert_eq!(slice, [2, 3]); +} + #[test] fn test_slice_from_mut() { let mut values = vec![1, 2, 3, 4, 5]; diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index a12a22fa26d8b..3c3bb68c67144 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -541,7 +541,7 @@ impl Pin

{ /// use std::pin::Pin; /// /// fn move_pinned_rc(mut x: Rc) { - /// let pinned = unsafe { Pin::new_unchecked(x.clone()) }; + /// let pinned = unsafe { Pin::new_unchecked(Rc::clone(&x)) }; /// { /// let p: Pin<&T> = pinned.as_ref(); /// // This should mean the pointee can never move again. diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 1aec7e1b5f871..38eabaaa396e0 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -76,7 +76,7 @@ //! fn main() { //! let spinlock = Arc::new(AtomicUsize::new(1)); //! -//! let spinlock_clone = spinlock.clone(); +//! let spinlock_clone = Arc::clone(&spinlock); //! let thread = thread::spawn(move|| { //! spinlock_clone.store(0, Ordering::SeqCst); //! }); diff --git a/library/profiler_builtins/build.rs b/library/profiler_builtins/build.rs index 2a5d5853fec64..7d5c601df535b 100644 --- a/library/profiler_builtins/build.rs +++ b/library/profiler_builtins/build.rs @@ -48,10 +48,10 @@ fn main() { // Turn off various features of gcc and such, mostly copying // compiler-rt's build system already cfg.flag("-fno-builtin"); - cfg.flag("-fvisibility=hidden"); cfg.flag("-fomit-frame-pointer"); cfg.define("VISIBILITY_HIDDEN", None); if !target.contains("windows") { + cfg.flag("-fvisibility=hidden"); cfg.define("COMPILER_RT_HAS_UNAME", Some("1")); } else { profile_sources.push("WindowsMMap.c"); diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 77cc5b93dbb50..57cb179a4244a 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -2382,7 +2382,7 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// use std::rc::Rc; /// /// let mut map: HashMap, u32> = HashMap::new(); - /// let mut known_strings: Vec> = Vec::new(); + /// let known_strings: Vec> = Vec::new(); /// /// // Initialise known strings, run program, etc. /// @@ -2390,7 +2390,7 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// /// fn reclaim_memory(map: &mut HashMap, u32>, known_strings: &[Rc] ) { /// for s in known_strings { - /// if let Entry::Occupied(entry) = map.entry(s.clone()) { + /// if let Entry::Occupied(entry) = map.entry(Rc::clone(s)) { /// // Replaces the entry's key with our version of it in `known_strings`. /// entry.replace_key(); /// } diff --git a/library/std/src/sync/barrier.rs b/library/std/src/sync/barrier.rs index 5d434791e9afb..204d7f3084f03 100644 --- a/library/std/src/sync/barrier.rs +++ b/library/std/src/sync/barrier.rs @@ -16,7 +16,7 @@ use crate::sync::{Condvar, Mutex}; /// let mut handles = Vec::with_capacity(10); /// let barrier = Arc::new(Barrier::new(10)); /// for _ in 0..10 { -/// let c = barrier.clone(); +/// let c = Arc::clone(&barrier); /// // The same messages will be printed together. /// // You will NOT see any interleaving. /// handles.push(thread::spawn(move|| { @@ -113,7 +113,7 @@ impl Barrier { /// let mut handles = Vec::with_capacity(10); /// let barrier = Arc::new(Barrier::new(10)); /// for _ in 0..10 { - /// let c = barrier.clone(); + /// let c = Arc::clone(&barrier); /// // The same messages will be printed together. /// // You will NOT see any interleaving. /// handles.push(thread::spawn(move|| { diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs index 651f813b3e227..bc01c26a86ace 100644 --- a/library/std/src/sync/condvar.rs +++ b/library/std/src/sync/condvar.rs @@ -36,7 +36,7 @@ impl WaitTimeoutResult { /// use std::time::Duration; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move || { /// let (lock, cvar) = &*pair2; @@ -93,7 +93,7 @@ impl WaitTimeoutResult { /// use std::thread; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); -/// let pair2 = pair.clone(); +/// let pair2 = Arc::clone(&pair); /// /// // Inside of our lock, spawn a new thread, and then wait for it to start. /// thread::spawn(move|| { @@ -176,7 +176,7 @@ impl Condvar { /// use std::thread; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move|| { /// let (lock, cvar) = &*pair2; @@ -232,7 +232,7 @@ impl Condvar { /// use std::thread; /// /// let pair = Arc::new((Mutex::new(true), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move|| { /// let (lock, cvar) = &*pair2; @@ -291,7 +291,7 @@ impl Condvar { /// use std::thread; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move|| { /// let (lock, cvar) = &*pair2; @@ -363,7 +363,7 @@ impl Condvar { /// use std::time::Duration; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move|| { /// let (lock, cvar) = &*pair2; @@ -432,7 +432,7 @@ impl Condvar { /// use std::time::Duration; /// /// let pair = Arc::new((Mutex::new(true), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move|| { /// let (lock, cvar) = &*pair2; @@ -496,7 +496,7 @@ impl Condvar { /// use std::thread; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move|| { /// let (lock, cvar) = &*pair2; @@ -536,7 +536,7 @@ impl Condvar { /// use std::thread; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move|| { /// let (lock, cvar) = &*pair2; diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index 0de717938348d..240155b06b411 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -88,7 +88,7 @@ use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult}; /// use std::thread; /// /// let lock = Arc::new(Mutex::new(0_u32)); -/// let lock2 = lock.clone(); +/// let lock2 = Arc::clone(&lock); /// /// let _ = thread::spawn(move || -> () { /// // This thread will acquire the mutex first, unwrapping the result of @@ -259,7 +259,7 @@ impl Mutex { /// use std::thread; /// /// let mutex = Arc::new(Mutex::new(0)); - /// let c_mutex = mutex.clone(); + /// let c_mutex = Arc::clone(&mutex); /// /// thread::spawn(move || { /// *c_mutex.lock().unwrap() = 10; @@ -295,7 +295,7 @@ impl Mutex { /// use std::thread; /// /// let mutex = Arc::new(Mutex::new(0)); - /// let c_mutex = mutex.clone(); + /// let c_mutex = Arc::clone(&mutex); /// /// thread::spawn(move || { /// let mut lock = c_mutex.try_lock(); @@ -331,7 +331,7 @@ impl Mutex { /// use std::thread; /// /// let mutex = Arc::new(Mutex::new(0)); - /// let c_mutex = mutex.clone(); + /// let c_mutex = Arc::clone(&mutex); /// /// let _ = thread::spawn(move || { /// let _lock = c_mutex.lock().unwrap(); diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index 2d219c2c7dd2a..f38d6101da0d3 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -165,7 +165,7 @@ impl RwLock { /// use std::thread; /// /// let lock = Arc::new(RwLock::new(1)); - /// let c_lock = lock.clone(); + /// let c_lock = Arc::clone(&lock); /// /// let n = lock.read().unwrap(); /// assert_eq!(*n, 1); @@ -321,7 +321,7 @@ impl RwLock { /// use std::thread; /// /// let lock = Arc::new(RwLock::new(0)); - /// let c_lock = lock.clone(); + /// let c_lock = Arc::clone(&lock); /// /// let _ = thread::spawn(move || { /// let _lock = c_lock.write().unwrap(); diff --git a/library/std/src/sys_common/poison.rs b/library/std/src/sys_common/poison.rs index 3f079da9098c7..2ab2c700a1bf1 100644 --- a/library/std/src/sys_common/poison.rs +++ b/library/std/src/sys_common/poison.rs @@ -65,7 +65,7 @@ pub struct Guard { /// let mutex = Arc::new(Mutex::new(1)); /// /// // poison the mutex -/// let c_mutex = mutex.clone(); +/// let c_mutex = Arc::clone(&mutex); /// let _ = thread::spawn(move || { /// let mut data = c_mutex.lock().unwrap(); /// *data = 2; @@ -168,7 +168,7 @@ impl PoisonError { /// let mutex = Arc::new(Mutex::new(HashSet::new())); /// /// // poison the mutex - /// let c_mutex = mutex.clone(); + /// let c_mutex = Arc::clone(&mutex); /// let _ = thread::spawn(move || { /// let mut data = c_mutex.lock().unwrap(); /// data.insert(10); diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 522d5bd3d9c36..aef4374c54232 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -523,7 +523,7 @@ jobs: - name: x86_64-mingw-1 env: SCRIPT: make ci-mingw-subset-1 - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-profiler CUSTOM_MINGW: 1 # FIXME(#59637) NO_DEBUG_ASSERTIONS: 1 @@ -533,7 +533,7 @@ jobs: - name: x86_64-mingw-2 env: SCRIPT: make ci-mingw-subset-2 - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-profiler CUSTOM_MINGW: 1 <<: *job-windows-xl diff --git a/src/doc/unstable-book/src/language-features/ffi-const.md b/src/doc/unstable-book/src/language-features/ffi-const.md index 9a1ced4033b22..24a304437542d 100644 --- a/src/doc/unstable-book/src/language-features/ffi-const.md +++ b/src/doc/unstable-book/src/language-features/ffi-const.md @@ -1,5 +1,9 @@ # `ffi_const` +The tracking issue for this feature is: [#58328] + +------ + The `#[ffi_const]` attribute applies clang's `const` attribute to foreign functions declarations. @@ -42,6 +46,7 @@ implemented in this way on all of them. It is therefore also worth verifying that the semantics of the C toolchain used to compile the binary being linked against are compatible with those of the `#[ffi_const]`. +[#58328]: https://github.com/rust-lang/rust/issues/58328 [ARM C/C++ compiler]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/Cacgigch.html [GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-const-function-attribute [IBM ILE C/C++]: https://www.ibm.com/support/knowledgecenter/fr/ssw_ibm_i_71/rzarg/fn_attrib_const.htm diff --git a/src/doc/unstable-book/src/language-features/ffi-pure.md b/src/doc/unstable-book/src/language-features/ffi-pure.md index 7bfd7a378f00b..4aef4eeab5532 100644 --- a/src/doc/unstable-book/src/language-features/ffi-pure.md +++ b/src/doc/unstable-book/src/language-features/ffi-pure.md @@ -1,5 +1,9 @@ # `ffi_pure` +The tracking issue for this feature is: [#58329] + +------ + The `#[ffi_pure]` attribute applies clang's `pure` attribute to foreign functions declarations. @@ -46,6 +50,7 @@ that the semantics of the C toolchain used to compile the binary being linked against are compatible with those of the `#[ffi_pure]`. +[#58329]: https://github.com/rust-lang/rust/issues/58329 [ARM C/C++ compiler]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/Cacigdac.html [GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-pure-function-attribute [IBM ILE C/C++]: https://www.ibm.com/support/knowledgecenter/fr/ssw_ibm_i_71/rzarg/fn_attrib_pure.htm diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index a458cdab30303..223fda84871e9 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -118,7 +118,7 @@ impl Item { self.attrs.collapsed_doc_value() } - pub fn links(&self) -> Vec<(String, String)> { + pub fn links(&self) -> Vec { self.attrs.links(&self.def_id.krate) } @@ -425,10 +425,38 @@ pub struct Attributes { pub cfg: Option>, pub span: Option, /// map from Rust paths to resolved defs and potential URL fragments - pub links: Vec<(String, Option, Option)>, + pub links: Vec, pub inner_docs: bool, } +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] +/// A link that has not yet been rendered. +/// +/// This link will be turned into a rendered link by [`Attributes::links`] +pub struct ItemLink { + /// The original link written in the markdown + pub(crate) link: String, + /// The link text displayed in the HTML. + /// + /// This may not be the same as `link` if there was a disambiguator + /// in an intra-doc link (e.g. \[`fn@f`\]) + pub(crate) link_text: String, + pub(crate) did: Option, + /// The url fragment to append to the link + pub(crate) fragment: Option, +} + +pub struct RenderedLink { + /// The text the link was original written as. + /// + /// This could potentially include disambiguators and backticks. + pub(crate) original_text: String, + /// The text to display in the HTML + pub(crate) new_text: String, + /// The URL to put in the `href` + pub(crate) href: String, +} + impl Attributes { /// Extracts the content from an attribute `#[doc(cfg(content))]`. pub fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> { @@ -605,21 +633,25 @@ impl Attributes { /// Gets links as a vector /// /// Cache must be populated before call - pub fn links(&self, krate: &CrateNum) -> Vec<(String, String)> { + pub fn links(&self, krate: &CrateNum) -> Vec { use crate::html::format::href; use crate::html::render::CURRENT_DEPTH; self.links .iter() - .filter_map(|&(ref s, did, ref fragment)| { - match did { + .filter_map(|ItemLink { link: s, link_text, did, fragment }| { + match *did { Some(did) => { if let Some((mut href, ..)) = href(did) { if let Some(ref fragment) = *fragment { href.push_str("#"); href.push_str(fragment); } - Some((s.clone(), href)) + Some(RenderedLink { + original_text: s.clone(), + new_text: link_text.clone(), + href, + }) } else { None } @@ -639,16 +671,17 @@ impl Attributes { }; // This is a primitive so the url is done "by hand". let tail = fragment.find('#').unwrap_or_else(|| fragment.len()); - Some(( - s.clone(), - format!( + Some(RenderedLink { + original_text: s.clone(), + new_text: link_text.clone(), + href: format!( "{}{}std/primitive.{}.html{}", url, if !url.ends_with('/') { "/" } else { "" }, &fragment[..tail], &fragment[tail..] ), - )) + }) } else { panic!("This isn't a primitive?!"); } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 098ece9a1d50e..a8c60e4a76df4 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -34,6 +34,7 @@ use std::fmt::Write; use std::ops::Range; use std::str; +use crate::clean::RenderedLink; use crate::doctest; use crate::html::highlight; use crate::html::toc::TocBuilder; @@ -52,7 +53,7 @@ fn opts() -> Options { pub struct Markdown<'a>( pub &'a str, /// A list of link replacements. - pub &'a [(String, String)], + pub &'a [RenderedLink], /// The current list of used header IDs. pub &'a mut IdMap, /// Whether to allow the use of explicit error codes in doctest lang strings. @@ -78,7 +79,7 @@ pub struct MarkdownHtml<'a>( pub &'a Option, ); /// A tuple struct like `Markdown` that renders only the first paragraph. -pub struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [(String, String)]); +pub struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [RenderedLink]); #[derive(Copy, Clone, PartialEq, Debug)] pub enum ErrorCodes { @@ -337,31 +338,107 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { } /// Make headings links with anchor IDs and build up TOC. -struct LinkReplacer<'a, 'b, I: Iterator>> { +struct LinkReplacer<'a, I: Iterator>> { inner: I, - links: &'b [(String, String)], + links: &'a [RenderedLink], + shortcut_link: Option<&'a RenderedLink>, } -impl<'a, 'b, I: Iterator>> LinkReplacer<'a, 'b, I> { - fn new(iter: I, links: &'b [(String, String)]) -> Self { - LinkReplacer { inner: iter, links } +impl<'a, I: Iterator>> LinkReplacer<'a, I> { + fn new(iter: I, links: &'a [RenderedLink]) -> Self { + LinkReplacer { inner: iter, links, shortcut_link: None } } } -impl<'a, 'b, I: Iterator>> Iterator for LinkReplacer<'a, 'b, I> { +impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { type Item = Event<'a>; fn next(&mut self) -> Option { - let event = self.inner.next(); - if let Some(Event::Start(Tag::Link(kind, dest, text))) = event { - if let Some(&(_, ref replace)) = self.links.iter().find(|link| link.0 == *dest) { - Some(Event::Start(Tag::Link(kind, replace.to_owned().into(), text))) - } else { - Some(Event::Start(Tag::Link(kind, dest, text))) + use pulldown_cmark::LinkType; + + let mut event = self.inner.next(); + + // Replace intra-doc links and remove disambiguators from shortcut links (`[fn@f]`). + match &mut event { + // This is a shortcut link that was resolved by the broken_link_callback: `[fn@f]` + // Remove any disambiguator. + Some(Event::Start(Tag::Link( + // [fn@f] or [fn@f][] + LinkType::ShortcutUnknown | LinkType::CollapsedUnknown, + dest, + title, + ))) => { + debug!("saw start of shortcut link to {} with title {}", dest, title); + // If this is a shortcut link, it was resolved by the broken_link_callback. + // So the URL will already be updated properly. + let link = self.links.iter().find(|&link| *link.href == **dest); + // Since this is an external iterator, we can't replace the inner text just yet. + // Store that we saw a link so we know to replace it later. + if let Some(link) = link { + trace!("it matched"); + assert!(self.shortcut_link.is_none(), "shortcut links cannot be nested"); + self.shortcut_link = Some(link); + } } - } else { - event + // Now that we're done with the shortcut link, don't replace any more text. + Some(Event::End(Tag::Link( + LinkType::ShortcutUnknown | LinkType::CollapsedUnknown, + dest, + _, + ))) => { + debug!("saw end of shortcut link to {}", dest); + if self.links.iter().find(|&link| *link.href == **dest).is_some() { + assert!(self.shortcut_link.is_some(), "saw closing link without opening tag"); + self.shortcut_link = None; + } + } + // Handle backticks in inline code blocks, but only if we're in the middle of a shortcut link. + // [`fn@f`] + Some(Event::Code(text)) => { + trace!("saw code {}", text); + if let Some(link) = self.shortcut_link { + trace!("original text was {}", link.original_text); + // NOTE: this only replaces if the code block is the *entire* text. + // If only part of the link has code highlighting, the disambiguator will not be removed. + // e.g. [fn@`f`] + // This is a limitation from `collect_intra_doc_links`: it passes a full link, + // and does not distinguish at all between code blocks. + // So we could never be sure we weren't replacing too much: + // [fn@my_`f`unc] is treated the same as [my_func()] in that pass. + // + // NOTE: &[1..len() - 1] is to strip the backticks + if **text == link.original_text[1..link.original_text.len() - 1] { + debug!("replacing {} with {}", text, link.new_text); + *text = CowStr::Borrowed(&link.new_text); + } + } + } + // Replace plain text in links, but only in the middle of a shortcut link. + // [fn@f] + Some(Event::Text(text)) => { + trace!("saw text {}", text); + if let Some(link) = self.shortcut_link { + trace!("original text was {}", link.original_text); + // NOTE: same limitations as `Event::Code` + if **text == *link.original_text { + debug!("replacing {} with {}", text, link.new_text); + *text = CowStr::Borrowed(&link.new_text); + } + } + } + // If this is a link, but not a shortcut link, + // replace the URL, since the broken_link_callback was not called. + Some(Event::Start(Tag::Link(_, dest, _))) => { + if let Some(link) = self.links.iter().find(|&link| *link.original_text == **dest) { + *dest = CowStr::Borrowed(link.href.as_ref()); + } + } + // Anything else couldn't have been a valid Rust path, so no need to replace the text. + _ => {} } + + // Yield the modified event + event } } @@ -855,8 +932,8 @@ impl Markdown<'_> { return String::new(); } let replacer = |_: &str, s: &str| { - if let Some(&(_, ref replace)) = links.iter().find(|link| &*link.0 == s) { - Some((replace.clone(), s.to_owned())) + if let Some(link) = links.iter().find(|link| &*link.original_text == s) { + Some((link.href.clone(), link.new_text.clone())) } else { None } @@ -933,8 +1010,8 @@ impl MarkdownSummaryLine<'_> { } let replacer = |_: &str, s: &str| { - if let Some(&(_, ref replace)) = links.iter().find(|link| &*link.0 == s) { - Some((replace.clone(), s.to_owned())) + if let Some(link) = links.iter().find(|link| &*link.original_text == s) { + Some((link.href.clone(), link.new_text.clone())) } else { None } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 57b3b9502a37f..f095f67b54c63 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -63,9 +63,8 @@ use rustc_span::symbol::{sym, Symbol}; use serde::ser::SerializeSeq; use serde::{Serialize, Serializer}; -use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy, TypeKind}; -use crate::config::RenderInfo; -use crate::config::RenderOptions; +use crate::clean::{self, AttributesExt, Deprecation, GetDefId, RenderedLink, SelfTy, TypeKind}; +use crate::config::{RenderInfo, RenderOptions}; use crate::docfs::{DocFS, PathError}; use crate::doctree; use crate::error::Error; @@ -1774,7 +1773,7 @@ fn render_markdown( w: &mut Buffer, cx: &Context, md_text: &str, - links: Vec<(String, String)>, + links: Vec, prefix: &str, is_hidden: bool, ) { diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index a4f5530815ce1..5d10e2e149b32 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -582,6 +582,9 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let parent_node = if item.is_fake() { // FIXME: is this correct? None + // If we're documenting the crate root itself, it has no parent. Use the root instead. + } else if item.def_id.is_top_level_module() { + Some(item.def_id) } else { let mut current = item.def_id; // The immediate parent might not always be a module. @@ -593,6 +596,12 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } current = parent; } else { + debug!( + "{:?} has no parent (kind={:?}, original was {:?})", + current, + self.cx.tcx.def_kind(current), + item.def_id + ); break None; } } @@ -697,11 +706,12 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { // This is an anchor to an element of the current page, nothing to do in here! continue; } - (parts[0].to_owned(), Some(parts[1].to_owned())) + (parts[0], Some(parts[1].to_owned())) } else { - (parts[0].to_owned(), None) + (parts[0], None) }; let resolved_self; + let link_text; let mut path_str; let disambiguator; let (mut res, mut fragment) = { @@ -718,6 +728,12 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { continue; } + // We stripped `()` and `!` when parsing the disambiguator. + // Add them back to be displayed, but not prefix disambiguators. + link_text = disambiguator + .map(|d| d.display_for(path_str)) + .unwrap_or_else(|| path_str.to_owned()); + // In order to correctly resolve intra-doc-links we need to // pick a base AST node to work from. If the documentation for // this module came from an inner comment (//!) then we anchor @@ -906,7 +922,12 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { if let Res::PrimTy(_) = res { match disambiguator { Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => { - item.attrs.links.push((ori_link, None, fragment)) + item.attrs.links.push(ItemLink { + link: ori_link, + link_text: path_str.to_owned(), + did: None, + fragment, + }); } Some(other) => { report_mismatch(other, Disambiguator::Primitive); @@ -957,7 +978,12 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } } let id = register_res(cx, res); - item.attrs.links.push((ori_link, Some(id), fragment)); + item.attrs.links.push(ItemLink { + link: ori_link, + link_text, + did: Some(id), + fragment, + }); } } @@ -985,6 +1011,18 @@ enum Disambiguator { } impl Disambiguator { + /// The text that should be displayed when the path is rendered as HTML. + /// + /// NOTE: `path` is not the original link given by the user, but a name suitable for passing to `resolve`. + fn display_for(&self, path: &str) -> String { + match self { + // FIXME: this will have different output if the user had `m!()` originally. + Self::Kind(DefKind::Macro(MacroKind::Bang)) => format!("{}!", path), + Self::Kind(DefKind::Fn) => format!("{}()", path), + _ => path.to_owned(), + } + } + /// (disambiguator, path_str) fn from_str(link: &str) -> Result<(Self, &str), ()> { use Disambiguator::{Kind, Namespace as NS, Primitive}; @@ -1037,7 +1075,7 @@ impl Disambiguator { } /// Return (description of the change, suggestion) - fn display_for(self, path_str: &str) -> (&'static str, String) { + fn suggestion_for(self, path_str: &str) -> (&'static str, String) { const PREFIX: &str = "prefix with the item kind"; const FUNCTION: &str = "add parentheses"; const MACRO: &str = "add an exclamation mark"; @@ -1292,7 +1330,7 @@ fn suggest_disambiguator( sp: Option, link_range: &Option>, ) { - let (action, mut suggestion) = disambiguator.display_for(path_str); + let (action, mut suggestion) = disambiguator.suggestion_for(path_str); let help = format!("to link to the {}, {}", disambiguator.descr(), action); if let Some(sp) = sp { diff --git a/src/llvm-project b/src/llvm-project index 45790d79496be..4d40ae500282d 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 45790d79496be37fbce6ec57abad5af8fa7a34d7 +Subproject commit 4d40ae500282dac444028358cbda8235f65e7e6a diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile index a16b4f61dcb5b..cb081fb641b0e 100644 --- a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile @@ -1,4 +1,8 @@ # needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. # ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and # `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/Makefile b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/Makefile index 08f311f17023d..ab826d07e056f 100644 --- a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/Makefile +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/Makefile @@ -1,5 +1,9 @@ # needs-profiler-support # ignore-msvc +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. # LINK_DEAD_CODE requires ignore-msvc due to Issue #76038 LINK_DEAD_CODE=yes @@ -8,4 +12,4 @@ LINK_DEAD_CODE=yes # ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and # `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. -# See ../instrument-coverage/coverage_tools.mk for more information. \ No newline at end of file +# See ../instrument-coverage/coverage_tools.mk for more information. diff --git a/src/test/run-make-fulldeps/pgo-branch-weights/Makefile b/src/test/run-make-fulldeps/pgo-branch-weights/Makefile index c13297b3a6141..18828b66ce874 100644 --- a/src/test/run-make-fulldeps/pgo-branch-weights/Makefile +++ b/src/test/run-make-fulldeps/pgo-branch-weights/Makefile @@ -1,4 +1,8 @@ # needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. -include ../tools.mk diff --git a/src/test/run-make-fulldeps/pgo-indirect-call-promotion/Makefile b/src/test/run-make-fulldeps/pgo-indirect-call-promotion/Makefile index e61018752c375..876a9b2c43991 100644 --- a/src/test/run-make-fulldeps/pgo-indirect-call-promotion/Makefile +++ b/src/test/run-make-fulldeps/pgo-indirect-call-promotion/Makefile @@ -1,4 +1,8 @@ # needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. -include ../tools.mk diff --git a/src/test/run-make-fulldeps/pgo-use/Makefile b/src/test/run-make-fulldeps/pgo-use/Makefile index 61a73587759fe..cb5e9e9a45580 100644 --- a/src/test/run-make-fulldeps/pgo-use/Makefile +++ b/src/test/run-make-fulldeps/pgo-use/Makefile @@ -1,4 +1,8 @@ # needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. -include ../tools.mk diff --git a/src/test/rustdoc-ui/doc-alias-assoc-const.rs b/src/test/rustdoc-ui/doc-alias-assoc-const.rs new file mode 100644 index 0000000000000..73e23c152f268 --- /dev/null +++ b/src/test/rustdoc-ui/doc-alias-assoc-const.rs @@ -0,0 +1,22 @@ +#![feature(doc_alias)] +#![feature(trait_alias)] + +pub struct Foo; + +pub trait Bar { + const BAZ: u8; +} + +impl Bar for Foo { + #[doc(alias = "CONST_BAZ")] //~ ERROR + const BAZ: u8 = 0; +} + +impl Foo { + #[doc(alias = "CONST_FOO")] // ok! + pub const FOO: u8 = 0; + + pub fn bar() -> u8 { + Self::FOO + } +} diff --git a/src/test/rustdoc-ui/doc-alias-assoc-const.stderr b/src/test/rustdoc-ui/doc-alias-assoc-const.stderr new file mode 100644 index 0000000000000..3c64548cc204d --- /dev/null +++ b/src/test/rustdoc-ui/doc-alias-assoc-const.stderr @@ -0,0 +1,8 @@ +error: `#[doc(alias = "...")]` isn't allowed on associated constant in trait implementation block + --> $DIR/doc-alias-assoc-const.rs:11:11 + | +LL | #[doc(alias = "CONST_BAZ")] + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/rustdoc/auxiliary/intra-link-pub-use.rs b/src/test/rustdoc/auxiliary/intra-link-pub-use.rs new file mode 100644 index 0000000000000..a4db2ffc445f8 --- /dev/null +++ b/src/test/rustdoc/auxiliary/intra-link-pub-use.rs @@ -0,0 +1,4 @@ +#![crate_name = "inner"] + +/// Documentation, including a link to [std::ptr] +pub fn f() {} diff --git a/src/test/rustdoc/intra-link-disambiguators-removed.rs b/src/test/rustdoc/intra-link-disambiguators-removed.rs new file mode 100644 index 0000000000000..26d05b484b919 --- /dev/null +++ b/src/test/rustdoc/intra-link-disambiguators-removed.rs @@ -0,0 +1,51 @@ +// ignore-tidy-linelength +#![deny(intra_doc_link_resolution_failure)] +// first try backticks +/// Trait: [`trait@Name`], fn: [`fn@Name`], [`Name`][`macro@Name`] +// @has intra_link_disambiguators_removed/struct.AtDisambiguator.html +// @has - '//a[@href="../intra_link_disambiguators_removed/trait.Name.html"][code]' "Name" +// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"][code]' "Name" +// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"][code]' "Name" +pub struct AtDisambiguator; + +/// fn: [`Name()`], macro: [`Name!`] +// @has intra_link_disambiguators_removed/struct.SymbolDisambiguator.html +// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"][code]' "Name()" +// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"][code]' "Name!" +pub struct SymbolDisambiguator; + +// Now make sure that backticks aren't added if they weren't already there +/// [fn@Name] +// @has intra_link_disambiguators_removed/trait.Name.html +// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"]' "Name" +// @!has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"][code]' "Name" + +// FIXME: this will turn !() into ! alone +/// [Name!()] +// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"]' "Name!" +pub trait Name {} + +#[allow(non_snake_case)] + +// Try collapsed reference links +/// [macro@Name][] +// @has intra_link_disambiguators_removed/fn.Name.html +// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"]' "Name" + +// Try links that have the same text as a generated URL +/// Weird URL aligned [../intra_link_disambiguators_removed/macro.Name.html][trait@Name] +// @has - '//a[@href="../intra_link_disambiguators_removed/trait.Name.html"]' "../intra_link_disambiguators_removed/macro.Name.html" +pub fn Name() {} + +#[macro_export] +// Rustdoc doesn't currently handle links that have weird interspersing of inline code blocks. +/// [fn@Na`m`e] +// @has intra_link_disambiguators_removed/macro.Name.html +// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"]' "fn@Name" + +// It also doesn't handle any case where the code block isn't the whole link text: +/// [trait@`Name`] +// @has - '//a[@href="../intra_link_disambiguators_removed/trait.Name.html"]' "trait@Name" +macro_rules! Name { + () => () +} diff --git a/src/test/rustdoc/intra-link-pub-use.rs b/src/test/rustdoc/intra-link-pub-use.rs new file mode 100644 index 0000000000000..dd52249abc6d0 --- /dev/null +++ b/src/test/rustdoc/intra-link-pub-use.rs @@ -0,0 +1,27 @@ +// aux-build: intra-link-pub-use.rs +#![deny(broken_intra_doc_links)] +#![crate_name = "outer"] + +extern crate inner; + +/// [mod@std::env] [g] + +// FIXME: This can't be tested because rustdoc doesn't show documentation on pub re-exports. +// Until then, comment out the `htmldocck` test. +// This test still does something; namely check that no incorrect errors are emitted when +// documenting the re-export. + +// @has outer/index.html +// @ has - '//a[@href="https://doc.rust-lang.org/nightly/std/env/fn.var.html"]' "std::env" +// @ has - '//a[@href="../outer/fn.f.html"]' "g" +pub use f as g; + +// FIXME: same as above +/// [std::env] +extern crate self as _; + +// Make sure the documentation is actually correct by documenting an inlined re-export +/// [mod@std::env] +// @has outer/fn.f.html +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/env/index.html"]' "std::env" +pub use inner::f; diff --git a/src/test/ui/array-slice-vec/vec-concat.rs b/src/test/ui/array-slice-vec/vec-concat.rs deleted file mode 100644 index 1f493679b7947..0000000000000 --- a/src/test/ui/array-slice-vec/vec-concat.rs +++ /dev/null @@ -1,14 +0,0 @@ -// run-pass - -use std::vec; - -pub fn main() { - let a: Vec = vec![1, 2, 3, 4, 5]; - let b: Vec = vec![6, 7, 8, 9, 0]; - let mut v: Vec = a; - v.extend_from_slice(&b); - println!("{}", v[9]); - assert_eq!(v[0], 1); - assert_eq!(v[7], 8); - assert_eq!(v[9], 0); -} diff --git a/src/test/ui/array-slice-vec/vec-growth.rs b/src/test/ui/array-slice-vec/vec-growth.rs deleted file mode 100644 index b09f08bb85a82..0000000000000 --- a/src/test/ui/array-slice-vec/vec-growth.rs +++ /dev/null @@ -1,16 +0,0 @@ -// run-pass - - - -pub fn main() { - let mut v = vec![1]; - v.push(2); - v.push(3); - v.push(4); - v.push(5); - assert_eq!(v[0], 1); - assert_eq!(v[1], 2); - assert_eq!(v[2], 3); - assert_eq!(v[3], 4); - assert_eq!(v[4], 5); -} diff --git a/src/test/ui/array-slice-vec/vec-push.rs b/src/test/ui/array-slice-vec/vec-push.rs deleted file mode 100644 index 466ab3fab1cab..0000000000000 --- a/src/test/ui/array-slice-vec/vec-push.rs +++ /dev/null @@ -1,3 +0,0 @@ -// run-pass - -pub fn main() { let mut v = vec![1, 2, 3]; v.push(1); } diff --git a/src/test/ui/array-slice-vec/vec-slice.rs b/src/test/ui/array-slice-vec/vec-slice.rs deleted file mode 100644 index 1f090ddd9c97d..0000000000000 --- a/src/test/ui/array-slice-vec/vec-slice.rs +++ /dev/null @@ -1,9 +0,0 @@ -// run-pass - - -pub fn main() { - let v = vec![1,2,3,4,5]; - let v2 = &v[1..3]; - assert_eq!(v2[0], 2); - assert_eq!(v2[1], 3); -} diff --git a/src/test/ui/array-slice-vec/vec-to_str.rs b/src/test/ui/array-slice-vec/vec-to_str.rs deleted file mode 100644 index a11cfc8e9b5c9..0000000000000 --- a/src/test/ui/array-slice-vec/vec-to_str.rs +++ /dev/null @@ -1,12 +0,0 @@ -// run-pass - - -pub fn main() { - assert_eq!(format!("{:?}", vec![0, 1]), "[0, 1]".to_string()); - - let foo = vec![3, 4]; - let bar: &[isize] = &[4, 5]; - - assert_eq!(format!("{:?}", foo), "[3, 4]"); - assert_eq!(format!("{:?}", bar), "[4, 5]"); -} diff --git a/src/test/ui/array-slice-vec/vec.rs b/src/test/ui/array-slice-vec/vec.rs deleted file mode 100644 index e76c1ab440e6e..0000000000000 --- a/src/test/ui/array-slice-vec/vec.rs +++ /dev/null @@ -1,15 +0,0 @@ -// run-pass - - - -pub fn main() { - let v: Vec = vec![10, 20]; - assert_eq!(v[0], 10); - assert_eq!(v[1], 20); - let mut x: usize = 0; - assert_eq!(v[x], 10); - assert_eq!(v[x + 1], 20); - x = x + 1; - assert_eq!(v[x], 20); - assert_eq!(v[x - 1], 10); -} diff --git a/src/test/ui/chalkify/type_inference.rs b/src/test/ui/chalkify/type_inference.rs index 2b62bf18a71ce..369777a7904af 100644 --- a/src/test/ui/chalkify/type_inference.rs +++ b/src/test/ui/chalkify/type_inference.rs @@ -24,5 +24,5 @@ fn main() { // Here we have two solutions so we get back the behavior of the old-style // trait solver. - only_bar(x); //~ ERROR the trait bound `f64: Bar` is not satisfied + only_bar(x); //~ ERROR the trait bound `{float}: Bar` is not satisfied } diff --git a/src/test/ui/chalkify/type_inference.stderr b/src/test/ui/chalkify/type_inference.stderr index 5cfb968404df6..fb8ccbfc660bf 100644 --- a/src/test/ui/chalkify/type_inference.stderr +++ b/src/test/ui/chalkify/type_inference.stderr @@ -1,11 +1,15 @@ -error[E0277]: the trait bound `f64: Bar` is not satisfied +error[E0277]: the trait bound `{float}: Bar` is not satisfied --> $DIR/type_inference.rs:27:5 | LL | fn only_bar(_x: T) { } | --- required by this bound in `only_bar` ... LL | only_bar(x); - | ^^^^^^^^ the trait `Bar` is not implemented for `f64` + | ^^^^^^^^ the trait `Bar` is not implemented for `{float}` + | + = help: the following implementations were found: + + error: aborting due to previous error diff --git a/src/test/ui/chalkify/type_wf.rs b/src/test/ui/chalkify/type_wf.rs index 7c469d99c5799..dd83a03fdf691 100644 --- a/src/test/ui/chalkify/type_wf.rs +++ b/src/test/ui/chalkify/type_wf.rs @@ -15,7 +15,7 @@ fn main() { x: 5, }; - let s = S { //~ ERROR the trait bound `f64: Foo` is not satisfied + let s = S { //~ ERROR the trait bound `{float}: Foo` is not satisfied x: 5.0, }; diff --git a/src/test/ui/chalkify/type_wf.stderr b/src/test/ui/chalkify/type_wf.stderr index ab585a6ed2140..3cd6036945493 100644 --- a/src/test/ui/chalkify/type_wf.stderr +++ b/src/test/ui/chalkify/type_wf.stderr @@ -1,11 +1,15 @@ -error[E0277]: the trait bound `f64: Foo` is not satisfied +error[E0277]: the trait bound `{float}: Foo` is not satisfied --> $DIR/type_wf.rs:18:13 | LL | struct S { | ---------------- required by `S` ... LL | let s = S { - | ^ the trait `Foo` is not implemented for `f64` + | ^ the trait `Foo` is not implemented for `{float}` + | + = help: the following implementations were found: + as Foo> + error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/issue-72793.rs b/src/test/ui/type-alias-impl-trait/issue-72793.rs new file mode 100644 index 0000000000000..e643a8cab5b02 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-72793.rs @@ -0,0 +1,27 @@ +// build-pass + +// Regression test for #72793. +// FIXME: This still shows ICE with `-Zmir-opt-level=2`. + +#![feature(type_alias_impl_trait)] + +trait T { type Item; } + +type Alias<'a> = impl T; + +struct S; +impl<'a> T for &'a S { + type Item = &'a (); +} + +fn filter_positive<'a>() -> Alias<'a> { + &S +} + +fn with_positive(fun: impl Fn(Alias<'_>)) { + fun(filter_positive()); +} + +fn main() { + with_positive(|_| ()); +} diff --git a/src/test/ui/union/union-deref.rs b/src/test/ui/union/union-deref.rs new file mode 100644 index 0000000000000..df598eea9ef0f --- /dev/null +++ b/src/test/ui/union/union-deref.rs @@ -0,0 +1,28 @@ +// ignore-tidy-linelength +//! Test the part of RFC 2514 that is about not applying `DerefMut` coercions +//! of union fields. +#![feature(untagged_unions)] + +use std::mem::ManuallyDrop; + +union U1 { x:(), f: ManuallyDrop<(T,)> } + +union U2 { x:(), f: (ManuallyDrop<(T,)>,) } + +fn main() { + let mut u : U1> = U1 { x: () }; + unsafe { (*u.f).0 = Vec::new() }; // explicit deref, this compiles + unsafe { u.f.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field + unsafe { &mut (*u.f).0 }; // explicit deref, this compiles + unsafe { &mut u.f.0 }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field + unsafe { (*u.f).0.push(0) }; // explicit deref, this compiles + unsafe { u.f.0.push(0) }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field + + let mut u : U2> = U2 { x: () }; + unsafe { (*u.f.0).0 = Vec::new() }; // explicit deref, this compiles + unsafe { u.f.0.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field + unsafe { &mut (*u.f.0).0 }; // explicit deref, this compiles + unsafe { &mut u.f.0.0 }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field + unsafe { (*u.f.0).0.push(0) }; // explicit deref, this compiles + unsafe { u.f.0.0.push(0) }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field +} diff --git a/src/test/ui/union/union-deref.stderr b/src/test/ui/union/union-deref.stderr new file mode 100644 index 0000000000000..fb16649767fb7 --- /dev/null +++ b/src/test/ui/union/union-deref.stderr @@ -0,0 +1,56 @@ +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:15:14 + | +LL | unsafe { u.f.0 = Vec::new() }; + | ^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:17:19 + | +LL | unsafe { &mut u.f.0 }; + | ^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:19:14 + | +LL | unsafe { u.f.0.push(0) }; + | ^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:23:14 + | +LL | unsafe { u.f.0.0 = Vec::new() }; + | ^^^^^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:25:19 + | +LL | unsafe { &mut u.f.0.0 }; + | ^^^^^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:27:14 + | +LL | unsafe { u.f.0.0.push(0) }; + | ^^^^^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: aborting due to 6 previous errors +