diff options
| author | The Miri Conjob Bot <miri@cron.bot> | 2023-07-07 06:34:22 +0000 |
|---|---|---|
| committer | The Miri Conjob Bot <miri@cron.bot> | 2023-07-07 06:34:22 +0000 |
| commit | b13a9fa3dd085a488c5bf911e921b273d322663b (patch) | |
| tree | 0b0748dd31e4b2956a38ea0c53e1f8cfcf3f528f | |
| parent | a5286fc6bf2892391b84ae9497da0aac04497185 (diff) | |
| parent | 8765f9172750111e0b7af489561fba0e2ef22007 (diff) | |
| download | rust-b13a9fa3dd085a488c5bf911e921b273d322663b.tar.gz rust-b13a9fa3dd085a488c5bf911e921b273d322663b.zip | |
Merge from rustc
571 files changed, 9941 insertions, 8882 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ff62e1ded61..3766adf7943 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,6 +37,7 @@ jobs: pr: name: "PR - ${{ matrix.name }}" env: + PR_CI_JOB: 1 CI_JOB_NAME: "${{ matrix.name }}" CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse HEAD_SHA: "${{ github.event.pull_request.head.sha || github.sha }}" @@ -211,18 +212,6 @@ jobs: - name: dist-loongarch64-linux os: ubuntu-20.04-8core-32gb env: {} - - name: dist-mips-linux - os: ubuntu-20.04-8core-32gb - env: {} - - name: dist-mips64-linux - os: ubuntu-20.04-8core-32gb - env: {} - - name: dist-mips64el-linux - os: ubuntu-20.04-8core-32gb - env: {} - - name: dist-mipsel-linux - os: ubuntu-20.04-8core-32gb - env: {} - name: dist-powerpc-linux os: ubuntu-20.04-8core-32gb env: {} @@ -308,10 +297,6 @@ jobs: env: RUST_BACKTRACE: 1 os: ubuntu-20.04-8core-32gb - - name: x86_64-gnu-llvm-14-stage1 - env: - RUST_BACKTRACE: 1 - os: ubuntu-20.04-8core-32gb - name: x86_64-gnu-nopt os: ubuntu-20.04-4core-16gb env: {} @@ -400,15 +385,10 @@ jobs: RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc" SCRIPT: make ci-msvc os: windows-2019-8core-32gb - - name: x86_64-msvc-cargo - env: - SCRIPT: python x.py --stage 2 test src/tools/cargotest src/tools/cargo - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-lld" - os: windows-2019-8core-32gb - - name: x86_64-msvc-tools + - name: x86_64-msvc-ext env: - SCRIPT: src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstate/toolstates.json windows - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstate/toolstates.json" + SCRIPT: python x.py --stage 2 test src/tools/cargotest src/tools/cargo && src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstate/toolstates.json windows + RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-lld --save-toolstates=/tmp/toolstate/toolstates.json" DEPLOY_TOOLSTATES_JSON: toolstates-windows.json os: windows-2019-8core-32gb - name: i686-mingw diff --git a/Cargo.lock b/Cargo.lock index 5bc2dc5eefa..5c936ca40e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -335,7 +335,7 @@ version = "0.1.0" dependencies = [ "anyhow", "curl", - "indexmap 1.9.3", + "indexmap 2.0.0", "serde", "serde_json", "toml 0.5.11", @@ -434,60 +434,6 @@ dependencies = [ ] [[package]] -name = "chalk-derive" -version = "0.92.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff5053a8a42dbff5279a82423946fc56dc1253b76cf211b2b3c14b3aad4e1281" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.8", - "synstructure 0.13.0", -] - -[[package]] -name = "chalk-engine" -version = "0.92.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d0e18f29b8b0f4dcf7d31fe00c884af67719699e381e8dcc9d9624b1621c60" -dependencies = [ - "chalk-derive", - "chalk-ir", - "chalk-solve", - "rustc-hash", - "tracing", -] - -[[package]] -name = "chalk-ir" -version = "0.92.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56de2146a8ed0fcd54f4bd50db852f1de4eac9e1efe568494f106c21b77d2a" -dependencies = [ - "bitflags 1.3.2", - "chalk-derive", - "lazy_static", -] - -[[package]] -name = "chalk-solve" -version = "0.92.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b392e02b4c81ec76d3748da839fc70a5539b83d27c9030668463d34d5110b860" -dependencies = [ - "chalk-derive", - "chalk-ir", - "ena", - "indexmap 1.9.3", - "itertools", - "petgraph", - "rustc-hash", - "tracing", - "tracing-subscriber", - "tracing-tree", -] - -[[package]] name = "chrono" version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -691,9 +637,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.93" +version = "0.1.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76630810d973ecea3dbf611e1b7aecfb1012751ef1ff8de3998f89014a166781" +checksum = "6866e0f3638013234db3c89ead7a14d278354338e7237257407500009012b23f" dependencies = [ "cc", "rustc-std-workspace-core", @@ -821,6 +767,16 @@ dependencies = [ ] [[package]] +name = "cstr" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11a39d776a3b35896711da8a04dc1835169dcd36f710878187637314e47941b" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] name = "ctrlc" version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1169,12 +1125,6 @@ dependencies = [ ] [[package]] -name = "fixedbitset" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" - -[[package]] name = "flate2" version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1694,8 +1644,6 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", - "rustc-rayon", - "serde", ] [[package]] @@ -1706,6 +1654,8 @@ checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ "equivalent", "hashbrown 0.14.0", + "rustc-rayon", + "serde", ] [[package]] @@ -2467,16 +2417,6 @@ dependencies = [ ] [[package]] -name = "petgraph" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" -dependencies = [ - "fixedbitset", - "indexmap 1.9.3", -] - -[[package]] name = "phf" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3086,6 +3026,7 @@ name = "rustc_codegen_llvm" version = "0.0.0" dependencies = [ "bitflags 1.3.2", + "cstr", "libc", "measureme", "object", @@ -3190,7 +3131,7 @@ dependencies = [ "cfg-if", "elsa", "ena", - "indexmap 1.9.3", + "indexmap 2.0.0", "itertools", "jobserver", "libc", @@ -3675,7 +3616,6 @@ name = "rustc_middle" version = "0.0.0" dependencies = [ "bitflags 1.3.2", - "chalk-ir", "derive_more", "either", "field-offset", @@ -3968,7 +3908,7 @@ dependencies = [ name = "rustc_serialize" version = "0.0.0" dependencies = [ - "indexmap 1.9.3", + "indexmap 2.0.0", "rustc_macros", "smallvec", "tempfile", @@ -4008,6 +3948,7 @@ dependencies = [ "rustc_hir", "rustc_middle", "rustc_span", + "scoped-tls", "tracing", ] @@ -4016,7 +3957,7 @@ name = "rustc_span" version = "0.0.0" dependencies = [ "cfg-if", - "indexmap 1.9.3", + "indexmap 2.0.0", "md-5", "rustc_arena", "rustc_data_structures", @@ -4102,9 +4043,6 @@ dependencies = [ name = "rustc_traits" version = "0.0.0" dependencies = [ - "chalk-engine", - "chalk-ir", - "chalk-solve", "rustc_ast", "rustc_data_structures", "rustc_hir", @@ -4136,6 +4074,7 @@ dependencies = [ name = "rustc_ty_utils" version = "0.0.0" dependencies = [ + "itertools", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", @@ -5032,7 +4971,6 @@ dependencies = [ "thread_local", "tracing", "tracing-core", - "tracing-log", ] [[package]] diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index a398fd80119..a7198fbf887 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2652,6 +2652,15 @@ pub struct NormalAttr { pub tokens: Option<LazyAttrTokenStream>, } +impl NormalAttr { + pub fn from_ident(ident: Ident) -> Self { + Self { + item: AttrItem { path: Path::from_ident(ident), args: AttrArgs::Empty, tokens: None }, + tokens: None, + } + } +} + #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub struct AttrItem { pub path: Path, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 29972dd76eb..dcaaaafedbe 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -673,14 +673,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_attrs( inner_hir_id, &[Attribute { - kind: AttrKind::Normal(ptr::P(NormalAttr { - item: AttrItem { - path: Path::from_ident(Ident::new(sym::track_caller, span)), - args: AttrArgs::Empty, - tokens: None, - }, - tokens: None, - })), + kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new(sym::track_caller, span)))), id: self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id(), style: AttrStyle::Outer, span: unstable_span, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 08ee3761bac..ab68436c093 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -3,6 +3,7 @@ use super::ResolverAstLoweringExt; use super::{AstOwner, ImplTraitContext, ImplTraitPosition}; use super::{FnDeclKind, LoweringContext, ParamMode}; +use hir::definitions::DefPathData; use rustc_ast::ptr::P; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; @@ -257,10 +258,11 @@ impl<'hir> LoweringContext<'_, 'hir> { ); let itctx = ImplTraitContext::Universal; - let (generics, decl) = this.lower_generics(generics, id, &itctx, |this| { - let ret_id = asyncness.opt_return_id(); - this.lower_fn_decl(&decl, id, *fn_sig_span, FnDeclKind::Fn, ret_id) - }); + let (generics, decl) = + this.lower_generics(generics, header.constness, id, &itctx, |this| { + let ret_id = asyncness.opt_return_id(); + this.lower_fn_decl(&decl, id, *fn_sig_span, FnDeclKind::Fn, ret_id) + }); let sig = hir::FnSig { decl, header: this.lower_fn_header(*header), @@ -295,6 +297,7 @@ impl<'hir> LoweringContext<'_, 'hir> { add_ty_alias_where_clause(&mut generics, *where_clauses, true); let (generics, ty) = self.lower_generics( &generics, + Const::No, id, &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| match ty { @@ -316,6 +319,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Enum(enum_definition, generics) => { let (generics, variants) = self.lower_generics( generics, + Const::No, id, &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -329,6 +333,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Struct(struct_def, generics) => { let (generics, struct_def) = self.lower_generics( generics, + Const::No, id, &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, struct_def), @@ -338,6 +343,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Union(vdata, generics) => { let (generics, vdata) = self.lower_generics( generics, + Const::No, id, &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, vdata), @@ -369,7 +375,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // parent lifetime. let itctx = ImplTraitContext::Universal; let (generics, (trait_ref, lowered_ty)) = - self.lower_generics(ast_generics, id, &itctx, |this| { + self.lower_generics(ast_generics, *constness, id, &itctx, |this| { let trait_ref = trait_ref.as_ref().map(|trait_ref| { this.lower_trait_ref( trait_ref, @@ -410,8 +416,15 @@ impl<'hir> LoweringContext<'_, 'hir> { })) } ItemKind::Trait(box Trait { is_auto, unsafety, generics, bounds, items }) => { + // FIXME(const_trait_impl, effects, fee1-dead) this should be simplified if possible + let constness = attrs + .unwrap_or(&[]) + .iter() + .find(|x| x.has_name(sym::const_trait)) + .map_or(Const::No, |x| Const::Yes(x.span)); let (generics, (unsafety, items, bounds)) = self.lower_generics( generics, + constness, id, &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -431,6 +444,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::TraitAlias(generics, bounds) => { let (generics, bounds) = self.lower_generics( generics, + Const::No, id, &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -593,7 +607,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let fdec = &sig.decl; let itctx = ImplTraitContext::Universal; let (generics, (fn_dec, fn_args)) = - self.lower_generics(generics, i.id, &itctx, |this| { + self.lower_generics(generics, Const::No, i.id, &itctx, |this| { ( // Disallow `impl Trait` in foreign items. this.lower_fn_decl( @@ -745,6 +759,7 @@ impl<'hir> LoweringContext<'_, 'hir> { add_ty_alias_where_clause(&mut generics, *where_clauses, false); let (generics, kind) = self.lower_generics( &generics, + Const::No, i.id, &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -843,6 +858,7 @@ impl<'hir> LoweringContext<'_, 'hir> { add_ty_alias_where_clause(&mut generics, *where_clauses, false); self.lower_generics( &generics, + Const::No, i.id, &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| match ty { @@ -1201,9 +1217,10 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) { let header = self.lower_fn_header(sig.header); let itctx = ImplTraitContext::Universal; - let (generics, decl) = self.lower_generics(generics, id, &itctx, |this| { - this.lower_fn_decl(&sig.decl, id, sig.span, kind, is_async) - }); + let (generics, decl) = + self.lower_generics(generics, sig.header.constness, id, &itctx, |this| { + this.lower_fn_decl(&sig.decl, id, sig.span, kind, is_async) + }); (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) } @@ -1275,6 +1292,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_generics<T>( &mut self, generics: &Generics, + constness: Const, parent_node_id: NodeId, itctx: &ImplTraitContext, f: impl FnOnce(&mut Self) -> T, @@ -1372,6 +1390,87 @@ impl<'hir> LoweringContext<'_, 'hir> { let impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds); predicates.extend(impl_trait_bounds.into_iter()); + // Desugar `~const` bound in generics into an additional `const host: bool` param + // if the effects feature is enabled. + if let Const::Yes(span) = constness && self.tcx.features().effects + // Do not add host param if it already has it (manually specified) + && !params.iter().any(|x| { + self.attrs.get(&x.hir_id.local_id).map_or(false, |attrs| { + attrs.iter().any(|x| x.has_name(sym::rustc_host)) + }) + }) + { + let param_node_id = self.next_node_id(); + let const_node_id = self.next_node_id(); + let def_id = self.create_def(self.local_def_id(parent_node_id), param_node_id, DefPathData::TypeNs(sym::host), span); + let anon_const: LocalDefId = self.create_def(def_id, const_node_id, DefPathData::AnonConst, span); + + let hir_id = self.next_id(); + let const_id = self.next_id(); + let const_expr_id = self.next_id(); + let bool_id = self.next_id(); + + self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); + self.children.push((anon_const, hir::MaybeOwner::NonOwner(const_id))); + + let attr_id = self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id(); + + let attrs = self.arena.alloc_from_iter([ + Attribute { + kind: AttrKind::Normal(P(NormalAttr::from_ident(Ident::new(sym::rustc_host, span)))), + span, + id: attr_id, + style: AttrStyle::Outer, + }, + ]); + self.attrs.insert(hir_id.local_id, attrs); + + let const_body = self.lower_body(|this| { + ( + &[], + hir::Expr { + hir_id: const_expr_id, + kind: hir::ExprKind::Lit( + this.arena.alloc(hir::Lit { node: LitKind::Bool(true), span }), + ), + span, + }, + ) + }); + + let param = hir::GenericParam { + def_id, + hir_id, + name: hir::ParamName::Plain(Ident { name: sym::host, span }), + span, + kind: hir::GenericParamKind::Const { + ty: self.arena.alloc(self.ty( + span, + hir::TyKind::Path(hir::QPath::Resolved( + None, + self.arena.alloc(hir::Path { + res: Res::PrimTy(hir::PrimTy::Bool), + span, + segments: self.arena.alloc_from_iter([hir::PathSegment { + ident: Ident { name: sym::bool, span }, + hir_id: bool_id, + res: Res::PrimTy(hir::PrimTy::Bool), + args: None, + infer_args: false, + }]), + }), + )), + )), + default: Some(hir::AnonConst { def_id: anon_const, hir_id: const_id, body: const_body }), + }, + colon_span: None, + pure_wrt_drop: false, + source: hir::GenericParamSource::Generics, + }; + + params.push(param); + } + let lowered_generics = self.arena.alloc(hir::Generics { params: self.arena.alloc_from_iter(params), predicates: self.arena.alloc_from_iter(predicates), diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 42e50fd0fad..d292611e6a2 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1050,7 +1050,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Some(def_id) => type_known_to_meet_bound_modulo_regions( &self.infcx, self.param_env, - tcx.mk_imm_ref(tcx.lifetimes.re_erased, ty), + Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty), def_id, ), _ => false, diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 8ec872e2057..617c85174cb 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -508,7 +508,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let generic_arg = substs[param_index as usize]; let identity_substs = InternalSubsts::identity_for_item(self.infcx.tcx, adt.did()); - let base_ty = self.infcx.tcx.mk_adt(*adt, identity_substs); + let base_ty = Ty::new_adt(self.infcx.tcx, *adt, identity_substs); let base_generic_arg = identity_substs[param_index as usize]; let adt_desc = adt.descr(); diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 2a0cb49672b..e45d3a2c882 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1139,7 +1139,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { _ => arg.fold_with(self), } }); - tcx.mk_opaque(def_id, tcx.mk_substs_from_iter(substs)) + Ty::new_opaque(tcx, def_id, tcx.mk_substs_from_iter(substs)) } } diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 4a872eb251c..1a227f2d110 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -158,7 +158,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) .emit() }); - prev.ty = infcx.tcx.ty_error(guar); + prev.ty = Ty::new_error(infcx.tcx, guar); } // Pick a better span if there is one. // FIXME(oli-obk): collect multiple spans for better diagnostics down the road. @@ -248,13 +248,13 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { instantiated_ty: OpaqueHiddenType<'tcx>, ) -> Ty<'tcx> { if let Some(e) = self.tainted_by_errors() { - return self.tcx.ty_error(e); + return Ty::new_error(self.tcx, e); } if let Err(guar) = check_opaque_type_parameter_valid(self.tcx, opaque_type_key, instantiated_ty.span) { - return self.tcx.ty_error(guar); + return Ty::new_error(self.tcx, guar); } let definition_ty = instantiated_ty @@ -271,7 +271,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { definition_ty, ) { Ok(hidden_ty) => hidden_ty, - Err(guar) => self.tcx.ty_error(guar), + Err(guar) => Ty::new_error(self.tcx, guar), } } } @@ -313,7 +313,7 @@ fn check_opaque_type_well_formed<'tcx>( // Require that the hidden type actually fulfills all the bounds of the opaque type, even without // the bounds that the function supplies. - let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), identity_substs); + let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), identity_substs); ocx.eq(&ObligationCause::misc(definition_span, def_id), param_env, opaque_ty, definition_ty) .map_err(|err| { infcx diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index c8ec1257d37..f22851d76b3 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -245,7 +245,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { .and(type_op::normalize::Normalize::new(ty)) .fully_perform(self.infcx, span) .unwrap_or_else(|guar| TypeOpOutput { - output: self.infcx.tcx.ty_error(guar), + output: Ty::new_error(self.infcx.tcx, guar), constraints: None, error_info: None, }); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 23c3b7b7016..7ed7e125b3c 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -237,7 +237,7 @@ pub(crate) fn type_check<'mir, 'tcx>( decl.hidden_type.span, format!("could not resolve {:#?}", hidden_type.ty.kind()), ); - hidden_type.ty = infcx.tcx.ty_error(reported); + hidden_type.ty = Ty::new_error(infcx.tcx, reported); } (opaque_type_key, hidden_type) @@ -520,7 +520,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { for elem in place.projection.iter() { if place_ty.variant_index.is_none() { if let Err(guar) = place_ty.ty.error_reported() { - return PlaceTy::from_ty(self.tcx().ty_error(guar)); + return PlaceTy::from_ty(Ty::new_error(self.tcx(), guar)); } } place_ty = self.sanitize_projection(place_ty, elem, place, location, context); @@ -656,7 +656,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { PlaceTy::from_ty(match base_ty.kind() { ty::Array(inner, _) => { assert!(!from_end, "array subslices should not use from_end"); - tcx.mk_array(*inner, to - from) + Ty::new_array(tcx, *inner, to - from) } ty::Slice(..) => { assert!(from_end, "slice subslices should use from_end"); @@ -749,7 +749,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } fn error(&mut self) -> Ty<'tcx> { - self.tcx().ty_error_misc() + Ty::new_misc_error(self.tcx()) } fn get_ambient_variance(&self, context: PlaceContext) -> ty::Variance { @@ -1918,7 +1918,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // and hence may contain unnormalized results. let fn_sig = self.normalize(fn_sig, location); - let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig); + let ty_fn_ptr_from = Ty::new_fn_ptr(tcx, fn_sig); if let Err(terr) = self.eq_types( *ty, @@ -1942,7 +1942,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ty::Closure(_, substs) => substs.as_closure().sig(), _ => bug!(), }; - let ty_fn_ptr_from = tcx.mk_fn_ptr(tcx.signature_unclosure(sig, *unsafety)); + let ty_fn_ptr_from = + Ty::new_fn_ptr(tcx, tcx.signature_unclosure(sig, *unsafety)); if let Err(terr) = self.eq_types( *ty, diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index c871703429a..7821b82bf2b 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -685,7 +685,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { assert_eq!(self.mir_def.to_def_id(), def_id); let resume_ty = substs.as_generator().resume_ty(); let output = substs.as_generator().return_ty(); - let generator_ty = tcx.mk_generator(def_id, substs, movability); + let generator_ty = Ty::new_generator(tcx, def_id, substs, movability); let inputs_and_output = self.infcx.tcx.mk_type_list(&[generator_ty, resume_ty, output]); ty::Binder::dummy(inputs_and_output) diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 84e09cf0abe..199fa6861cf 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -665,7 +665,8 @@ pub(crate) fn codegen_drop<'tcx>( let arg_value = drop_place.place_ref( fx, - fx.layout_of(fx.tcx.mk_ref( + fx.layout_of(Ty::new_ref( + fx.tcx, fx.tcx.lifetimes.re_erased, TypeAndMut { ty, mutbl: crate::rustc_hir::Mutability::Mut }, )), diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index ce10780f9de..826ce60ed13 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -706,7 +706,6 @@ fn codegen_stmt<'tcx>( let times = fx .monomorphize(times) .eval(fx.tcx, ParamEnv::reveal_all()) - .kind() .try_to_bits(fx.tcx.data_layout.pointer_size) .unwrap(); if operand.layout().size.bytes() == 0 { @@ -747,7 +746,7 @@ fn codegen_stmt<'tcx>( } Rvalue::ShallowInitBox(ref operand, content_ty) => { let content_ty = fx.monomorphize(content_ty); - let box_layout = fx.layout_of(fx.tcx.mk_box(content_ty)); + let box_layout = fx.layout_of(Ty::new_box(fx.tcx, content_ty)); let operand = codegen_operand(fx, operand); let operand = operand.load_scalar(fx); lval.write_cvalue(fx, CValue::by_val(operand, box_layout)); @@ -888,7 +887,7 @@ pub(crate) fn codegen_place<'tcx>( let ptr = cplace.to_ptr(); cplace = CPlace::for_ptr( ptr.offset_i64(fx, elem_layout.size.bytes() as i64 * (from as i64)), - fx.layout_of(fx.tcx.mk_array(*elem_ty, to - from)), + fx.layout_of(Ty::new_array(fx.tcx, *elem_ty, to - from)), ); } ty::Slice(elem_ty) => { diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs index 13568b198db..b2bc289a5b6 100644 --- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs +++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs @@ -92,7 +92,7 @@ pub(crate) fn maybe_codegen_checked<'tcx>( match bin_op { BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => unreachable!(), BinOp::Mul if is_signed => { - let out_ty = fx.tcx.mk_tup(&[lhs.layout().ty, fx.tcx.types.bool]); + let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]); let oflow = CPlace::new_stack_slot(fx, fx.layout_of(fx.tcx.types.i32)); let lhs = lhs.load_scalar(fx); let rhs = rhs.load_scalar(fx); @@ -112,7 +112,7 @@ pub(crate) fn maybe_codegen_checked<'tcx>( Some(CValue::by_val_pair(res, oflow, fx.layout_of(out_ty))) } BinOp::Add | BinOp::Sub | BinOp::Mul => { - let out_ty = fx.tcx.mk_tup(&[lhs.layout().ty, fx.tcx.types.bool]); + let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]); let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty)); let param_types = vec![ AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn), diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index a694bb26afb..67ea20112fe 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -99,7 +99,7 @@ fn clif_pair_type_from_ty<'tcx>( /// Is a pointer to this type a fat ptr? pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { - let ptr_ty = tcx.mk_ptr(TypeAndMut { ty, mutbl: rustc_hir::Mutability::Not }); + let ptr_ty = Ty::new_ptr(tcx, TypeAndMut { ty, mutbl: rustc_hir::Mutability::Not }); match &tcx.layout_of(ParamEnv::reveal_all().and(ptr_ty)).unwrap().abi { Abi::Scalar(_) => false, Abi::ScalarPair(_, _) => true, diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs index bbd5f4be783..24ad0083a22 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs @@ -386,7 +386,7 @@ fn llvm_add_sub<'tcx>( // carry0 | carry1 -> carry or borrow respectively let cb_out = fx.bcx.ins().bor(cb0, cb1); - let layout = fx.layout_of(fx.tcx.mk_tup(&[fx.tcx.types.u8, fx.tcx.types.u64])); + let layout = fx.layout_of(Ty::new_tup(fx.tcx, &[fx.tcx.types.u8, fx.tcx.types.u64])); let val = CValue::by_val_pair(cb_out, c, layout); ret.write_cvalue(fx, val); } diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs index ac1a6cce096..8992f40fb90 100644 --- a/compiler/rustc_codegen_cranelift/src/num.rs +++ b/compiler/rustc_codegen_cranelift/src/num.rs @@ -270,7 +270,7 @@ pub(crate) fn codegen_checked_int_binop<'tcx>( _ => bug!("binop {:?} on checked int/uint lhs: {:?} rhs: {:?}", bin_op, in_lhs, in_rhs), }; - let out_layout = fx.layout_of(fx.tcx.mk_tup(&[in_lhs.layout().ty, fx.tcx.types.bool])); + let out_layout = fx.layout_of(Ty::new_tup(fx.tcx, &[in_lhs.layout().ty, fx.tcx.types.bool])); CValue::by_val_pair(res, has_overflow, out_layout) } diff --git a/compiler/rustc_codegen_gcc/src/coverageinfo.rs b/compiler/rustc_codegen_gcc/src/coverageinfo.rs index 872fc2472e2..849e9886ef3 100644 --- a/compiler/rustc_codegen_gcc/src/coverageinfo.rs +++ b/compiler/rustc_codegen_gcc/src/coverageinfo.rs @@ -1,69 +1,11 @@ -use gccjit::RValue; -use rustc_codegen_ssa::traits::{CoverageInfoBuilderMethods, CoverageInfoMethods}; -use rustc_hir::def_id::DefId; -use rustc_middle::mir::coverage::{ - CodeRegion, - CounterValueReference, - ExpressionOperandId, - InjectedExpressionId, - Op, -}; +use rustc_codegen_ssa::traits::CoverageInfoBuilderMethods; +use rustc_middle::mir::Coverage; use rustc_middle::ty::Instance; use crate::builder::Builder; -use crate::context::CodegenCx; impl<'a, 'gcc, 'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { - fn set_function_source_hash( - &mut self, - _instance: Instance<'tcx>, - _function_source_hash: u64, - ) -> bool { - unimplemented!(); - } - - fn add_coverage_counter(&mut self, _instance: Instance<'tcx>, _id: CounterValueReference, _region: CodeRegion) -> bool { - // TODO(antoyo) - false - } - - fn add_coverage_counter_expression(&mut self, _instance: Instance<'tcx>, _id: InjectedExpressionId, _lhs: ExpressionOperandId, _op: Op, _rhs: ExpressionOperandId, _region: Option<CodeRegion>) -> bool { - // TODO(antoyo) - false - } - - fn add_coverage_unreachable(&mut self, _instance: Instance<'tcx>, _region: CodeRegion) -> bool { + fn add_coverage(&mut self, _instance: Instance<'tcx>, _coverage: &Coverage) { // TODO(antoyo) - false - } -} - -impl<'gcc, 'tcx> CoverageInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { - fn coverageinfo_finalize(&self) { - // TODO(antoyo) - } - - fn get_pgo_func_name_var(&self, _instance: Instance<'tcx>) -> RValue<'gcc> { - unimplemented!(); - } - - /// Functions with MIR-based coverage are normally codegenned _only_ if - /// called. LLVM coverage tools typically expect every function to be - /// defined (even if unused), with at least one call to LLVM intrinsic - /// `instrprof.increment`. - /// - /// Codegen a small function that will never be called, with one counter - /// that will never be incremented. - /// - /// For used/called functions, the coverageinfo was already added to the - /// `function_coverage_map` (keyed by function `Instance`) during codegen. - /// But in this case, since the unused function was _not_ previously - /// codegenned, collect the coverage `CodeRegion`s from the MIR and add - /// them. The first `CodeRegion` is used to add a single counter, with the - /// same counter ID used in the injected `instrprof.increment` intrinsic - /// call. Since the function is never called, all other `CodeRegion`s can be - /// added as `unreachable_region`s. - fn define_unused_fn(&self, _def_id: DefId) { - unimplemented!(); } } diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index a31fee39918..0b208be4e62 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -1147,19 +1147,19 @@ fn get_rust_try_fn<'a, 'gcc, 'tcx>(cx: &'a CodegenCx<'gcc, 'tcx>, codegen: &mut // Define the type up front for the signature of the rust_try function. let tcx = cx.tcx; - let i8p = tcx.mk_mut_ptr(tcx.types.i8); + let i8p = Ty::new_mut_ptr(tcx,tcx.types.i8); // `unsafe fn(*mut i8) -> ()` - let try_fn_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig( + let try_fn_ty = Ty::new_fn_ptr(tcx,ty::Binder::dummy(tcx.mk_fn_sig( iter::once(i8p), - tcx.mk_unit(), + Ty::new_unit(tcx,), false, rustc_hir::Unsafety::Unsafe, Abi::Rust, ))); // `unsafe fn(*mut i8, *mut i8) -> ()` - let catch_fn_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig( + let catch_fn_ty = Ty::new_fn_ptr(tcx,ty::Binder::dummy(tcx.mk_fn_sig( [i8p, i8p].iter().cloned(), - tcx.mk_unit(), + Ty::new_unit(tcx,), false, rustc_hir::Unsafety::Unsafe, Abi::Rust, diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index 74f016cf90a..e0823888f67 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -283,7 +283,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { // only wide pointer boxes are handled as pointers // thin pointer boxes with scalar allocators are handled by the general logic below ty::Adt(def, substs) if def.is_box() && cx.layout_of(substs.type_at(1)).is_zst() => { - let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty()); + let ptr_ty = Ty::new_mut_ptr(cx.tcx,self.ty.boxed_ty()); return cx.layout_of(ptr_ty).scalar_pair_element_gcc_type(cx, index, immediate); } _ => {} diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 39ff3a0ba2d..ad51f2d0958 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -8,6 +8,7 @@ test = false [dependencies] bitflags = "1.0" +cstr = "0.2" libc = "0.2" measureme = "10.0.0" object = { version = "0.31.1", default-features = false, features = [ diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 28be6d033f8..d221bad28ef 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -351,7 +351,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { continue; } PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { - let ptr_ty = cx.tcx.mk_mut_ptr(arg.layout.ty); + let ptr_ty = Ty::new_mut_ptr(cx.tcx, arg.layout.ty); let ptr_layout = cx.layout_of(ptr_ty); llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 0, true)); llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 1, true)); diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index ad0636894b7..a57508815d6 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -77,7 +77,7 @@ pub(crate) unsafe fn codegen( llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty); llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden); - let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, c"entry".as_ptr().cast()); + let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast()); let llbuilder = llvm::LLVMCreateBuilderInContext(llcx); llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb); @@ -129,7 +129,7 @@ pub(crate) unsafe fn codegen( attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]); llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden); - let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, c"entry".as_ptr().cast()); + let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast()); let llbuilder = llvm::LLVMCreateBuilderInContext(llcx); llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb); diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 94885b40cc1..d7dd98d7938 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -601,7 +601,7 @@ pub(crate) fn run_pass_manager( llvm::LLVMRustAddModuleFlag( module.module_llvm.llmod(), llvm::LLVMModFlagBehavior::Error, - c"LTOPostLink".as_ptr().cast(), + "LTOPostLink\0".as_ptr().cast(), 1, ); } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 998e3b300da..0f5e975445f 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -931,16 +931,16 @@ unsafe fn embed_bitcode( let llglobal = llvm::LLVMAddGlobal( llmod, common::val_ty(llconst), - c"rustc.embedded.module".as_ptr().cast(), + "rustc.embedded.module\0".as_ptr().cast(), ); llvm::LLVMSetInitializer(llglobal, llconst); let section = if is_apple { - c"__LLVM,__bitcode" + "__LLVM,__bitcode\0" } else if is_aix { - c".ipa" + ".ipa\0" } else { - c".llvmbc" + ".llvmbc\0" }; llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); @@ -950,15 +950,15 @@ unsafe fn embed_bitcode( let llglobal = llvm::LLVMAddGlobal( llmod, common::val_ty(llconst), - c"rustc.embedded.cmdline".as_ptr().cast(), + "rustc.embedded.cmdline\0".as_ptr().cast(), ); llvm::LLVMSetInitializer(llglobal, llconst); let section = if is_apple { - c"__LLVM,__cmdline" + "__LLVM,__cmdline\0" } else if is_aix { - c".info" + ".info\0" } else { - c".llvmcmd" + ".llvmcmd\0" }; llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 2f7eb08ad3d..5b2bbdb4bde 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -19,6 +19,8 @@ use crate::context::CodegenCx; use crate::llvm; use crate::value::Value; +use cstr::cstr; + use rustc_codegen_ssa::base::maybe_create_entry_wrapper; use rustc_codegen_ssa::mono_item::MonoItemExt; use rustc_codegen_ssa::traits::*; @@ -108,11 +110,11 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol) -> (ModuleCodegen // Create the llvm.used and llvm.compiler.used variables. if !cx.used_statics.borrow().is_empty() { - cx.create_used_variable_impl(c"llvm.used", &*cx.used_statics.borrow()); + cx.create_used_variable_impl(cstr!("llvm.used"), &*cx.used_statics.borrow()); } if !cx.compiler_used_statics.borrow().is_empty() { cx.create_used_variable_impl( - c"llvm.compiler.used", + cstr!("llvm.compiler.used"), &*cx.compiler_used_statics.borrow(), ); } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 9863ca35202..d55992bf092 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -6,6 +6,7 @@ use crate::llvm::{self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, False, True} use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; +use cstr::cstr; use libc::{c_char, c_uint}; use rustc_codegen_ssa::common::{IntPredicate, RealPredicate, SynchronizationScope, TypeKind}; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; @@ -25,6 +26,7 @@ use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange}; use rustc_target::spec::{HasTargetSpec, SanitizerSet, Target}; use smallvec::SmallVec; use std::borrow::Cow; +use std::ffi::CStr; use std::iter; use std::ops::Deref; use std::ptr; @@ -44,10 +46,13 @@ impl Drop for Builder<'_, '_, '_> { } } +// FIXME(eddyb) use a checked constructor when they become `const fn`. +const EMPTY_C_STR: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"\0") }; + /// Empty string, to be used where LLVM expects an instruction name, indicating /// that the instruction is to be left unnamed (i.e. numbered, in textual IR). // FIXME(eddyb) pass `&CStr` directly to FFI once it's a thin pointer. -const UNNAMED: *const c_char = c"".as_ptr(); +const UNNAMED: *const c_char = EMPTY_C_STR.as_ptr(); impl<'ll, 'tcx> BackendTypes for Builder<'_, 'll, 'tcx> { type Value = <CodegenCx<'ll, 'tcx> as BackendTypes>::Value; @@ -1002,13 +1007,14 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn cleanup_pad(&mut self, parent: Option<&'ll Value>, args: &[&'ll Value]) -> Funclet<'ll> { + let name = cstr!("cleanuppad"); let ret = unsafe { llvm::LLVMBuildCleanupPad( self.llbuilder, parent, args.as_ptr(), args.len() as c_uint, - c"cleanuppad".as_ptr(), + name.as_ptr(), ) }; Funclet::new(ret.expect("LLVM does not have support for cleanuppad")) @@ -1022,13 +1028,14 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn catch_pad(&mut self, parent: &'ll Value, args: &[&'ll Value]) -> Funclet<'ll> { + let name = cstr!("catchpad"); let ret = unsafe { llvm::LLVMBuildCatchPad( self.llbuilder, parent, args.as_ptr(), args.len() as c_uint, - c"catchpad".as_ptr(), + name.as_ptr(), ) }; Funclet::new(ret.expect("LLVM does not have support for catchpad")) @@ -1040,13 +1047,14 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unwind: Option<&'ll BasicBlock>, handlers: &[&'ll BasicBlock], ) -> &'ll Value { + let name = cstr!("catchswitch"); let ret = unsafe { llvm::LLVMBuildCatchSwitch( self.llbuilder, parent, unwind, handlers.len() as c_uint, - c"catchswitch".as_ptr(), + name.as_ptr(), ) }; let ret = ret.expect("LLVM does not have support for catchswitch"); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 2087754c66b..df52f50f86f 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -8,6 +8,7 @@ use crate::llvm::{self, True}; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; +use cstr::cstr; use rustc_codegen_ssa::traits::*; use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; @@ -481,9 +482,9 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> { .all(|&byte| byte == 0); let sect_name = if all_bytes_are_zero { - c"__DATA,__thread_bss" + cstr!("__DATA,__thread_bss") } else { - c"__DATA,__thread_data" + cstr!("__DATA,__thread_data") }; llvm::LLVMSetSection(g, sect_name.as_ptr()); } @@ -512,7 +513,7 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> { let val = llvm::LLVMMetadataAsValue(self.llcx, meta); llvm::LLVMAddNamedMetadataOperand( self.llmod, - c"wasm.custom_sections".as_ptr().cast(), + "wasm.custom_sections\0".as_ptr().cast(), val, ); } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 287a22bc9a6..e1e0a442845 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -8,6 +8,7 @@ use crate::llvm_util; use crate::type_::Type; use crate::value::Value; +use cstr::cstr; use rustc_codegen_ssa::base::{wants_msvc_seh, wants_wasm_eh}; use rustc_codegen_ssa::traits::*; use rustc_data_structures::base_n; @@ -223,42 +224,36 @@ pub unsafe fn create_module<'ll>( // If skipping the PLT is enabled, we need to add some module metadata // to ensure intrinsic calls don't use it. if !sess.needs_plt() { - llvm::LLVMRustAddModuleFlag( - llmod, - llvm::LLVMModFlagBehavior::Warning, - c"RtLibUseGOT".as_ptr().cast(), - 1, - ); + let avoid_plt = "RtLibUseGOT\0".as_ptr().cast(); + llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1); } // Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.) if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() { + let canonical_jump_tables = "CFI Canonical Jump Tables\0".as_ptr().cast(); llvm::LLVMRustAddModuleFlag( llmod, llvm::LLVMModFlagBehavior::Override, - c"CFI Canonical Jump Tables".as_ptr().cast(), + canonical_jump_tables, 1, ); } // Enable LTO unit splitting if specified or if CFI is enabled. (See https://reviews.llvm.org/D53891.) if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() { + let enable_split_lto_unit = "EnableSplitLTOUnit\0".as_ptr().cast(); llvm::LLVMRustAddModuleFlag( llmod, llvm::LLVMModFlagBehavior::Override, - c"EnableSplitLTOUnit".as_ptr().cast(), + enable_split_lto_unit, 1, ); } // Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.) if sess.is_sanitizer_kcfi_enabled() { - llvm::LLVMRustAddModuleFlag( - llmod, - llvm::LLVMModFlagBehavior::Override, - c"kcfi".as_ptr().cast(), - 1, - ); + let kcfi = "kcfi\0".as_ptr().cast(); + llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1); } // Control Flow Guard is currently only supported by the MSVC linker on Windows. @@ -270,7 +265,7 @@ pub unsafe fn create_module<'ll>( llvm::LLVMRustAddModuleFlag( llmod, llvm::LLVMModFlagBehavior::Warning, - c"cfguard".as_ptr() as *const _, + "cfguard\0".as_ptr() as *const _, 1, ) } @@ -279,7 +274,7 @@ pub unsafe fn create_module<'ll>( llvm::LLVMRustAddModuleFlag( llmod, llvm::LLVMModFlagBehavior::Warning, - c"cfguard".as_ptr() as *const _, + "cfguard\0".as_ptr() as *const _, 2, ) } @@ -297,26 +292,26 @@ pub unsafe fn create_module<'ll>( llvm::LLVMRustAddModuleFlag( llmod, behavior, - c"branch-target-enforcement".as_ptr().cast(), + "branch-target-enforcement\0".as_ptr().cast(), bti.into(), ); llvm::LLVMRustAddModuleFlag( llmod, behavior, - c"sign-return-address".as_ptr().cast(), + "sign-return-address\0".as_ptr().cast(), pac_ret.is_some().into(), ); let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A }); llvm::LLVMRustAddModuleFlag( llmod, behavior, - c"sign-return-address-all".as_ptr().cast(), + "sign-return-address-all\0".as_ptr().cast(), pac_opts.leaf.into(), ); llvm::LLVMRustAddModuleFlag( llmod, behavior, - c"sign-return-address-with-bkey".as_ptr().cast(), + "sign-return-address-with-bkey\0".as_ptr().cast(), u32::from(pac_opts.key == PAuthKey::B), ); } else { @@ -332,7 +327,7 @@ pub unsafe fn create_module<'ll>( llvm::LLVMRustAddModuleFlag( llmod, llvm::LLVMModFlagBehavior::Override, - c"cf-protection-branch".as_ptr().cast(), + "cf-protection-branch\0".as_ptr().cast(), 1, ) } @@ -340,7 +335,7 @@ pub unsafe fn create_module<'ll>( llvm::LLVMRustAddModuleFlag( llmod, llvm::LLVMModFlagBehavior::Override, - c"cf-protection-return".as_ptr().cast(), + "cf-protection-return\0".as_ptr().cast(), 1, ) } @@ -349,7 +344,7 @@ pub unsafe fn create_module<'ll>( llvm::LLVMRustAddModuleFlag( llmod, llvm::LLVMModFlagBehavior::Error, - c"Virtual Function Elim".as_ptr().cast(), + "Virtual Function Elim\0".as_ptr().cast(), 1, ); } @@ -481,13 +476,14 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { } pub(crate) fn create_used_variable_impl(&self, name: &'static CStr, values: &[&'ll Value]) { + let section = cstr!("llvm.metadata"); let array = self.const_array(self.type_ptr_to(self.type_i8()), values); unsafe { let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr()); llvm::LLVMSetInitializer(g, array); llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage); - llvm::LLVMSetSection(g, c"llvm.metadata".as_ptr()); + llvm::LLVMSetSection(g, section.as_ptr()); } } } diff --git a/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs index 1791ce4b315..1791ce4b315 100644 --- a/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs diff --git a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs index e4da3b8de05..06844afd6b8 100644 --- a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs @@ -1,6 +1,7 @@ pub use super::ffi::*; use rustc_index::{IndexSlice, IndexVec}; +use rustc_middle::bug; use rustc_middle::mir::coverage::{ CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId, InjectedExpressionIndex, MappedExpressionIndex, Op, diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 21a1ac34844..a1ff2aa6625 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -1,10 +1,10 @@ use crate::common::CodegenCx; use crate::coverageinfo; +use crate::coverageinfo::map_data::{Counter, CounterExpression}; use crate::llvm; use llvm::coverageinfo::CounterMappingRegion; -use rustc_codegen_ssa::coverageinfo::map::{Counter, CounterExpression}; -use rustc_codegen_ssa::traits::{ConstMethods, CoverageInfoMethods}; +use rustc_codegen_ssa::traits::ConstMethods; use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index cd261293e9b..42fdbd78618 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -3,13 +3,13 @@ use crate::llvm; use crate::abi::Abi; use crate::builder::Builder; use crate::common::CodegenCx; +use crate::coverageinfo::map_data::{CounterExpression, FunctionCoverage}; use libc::c_uint; use llvm::coverageinfo::CounterMappingRegion; -use rustc_codegen_ssa::coverageinfo::map::{CounterExpression, FunctionCoverage}; use rustc_codegen_ssa::traits::{ - BaseTypeMethods, BuilderMethods, ConstMethods, CoverageInfoBuilderMethods, CoverageInfoMethods, - MiscMethods, StaticMethods, + BaseTypeMethods, BuilderMethods, ConstMethods, CoverageInfoBuilderMethods, MiscMethods, + StaticMethods, }; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; @@ -17,16 +17,20 @@ use rustc_hir::def_id::DefId; use rustc_llvm::RustString; use rustc_middle::bug; use rustc_middle::mir::coverage::{ - CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId, Op, + CodeRegion, CounterValueReference, CoverageKind, ExpressionOperandId, InjectedExpressionId, Op, }; +use rustc_middle::mir::Coverage; use rustc_middle::ty; -use rustc_middle::ty::layout::FnAbiOf; +use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::Instance; +use rustc_middle::ty::Ty; use std::cell::RefCell; use std::ffi::CString; +mod ffi; +pub(crate) mod map_data; pub mod mapgen; const UNUSED_FUNCTION_COUNTER_ID: CounterValueReference = CounterValueReference::START; @@ -53,11 +57,17 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> { } } -impl<'ll, 'tcx> CoverageInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { - fn coverageinfo_finalize(&self) { +// These methods used to be part of trait `CoverageInfoMethods`, which no longer +// exists after most coverage code was moved out of SSA. +impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { + pub(crate) fn coverageinfo_finalize(&self) { mapgen::finalize(self) } + /// For LLVM codegen, returns a function-specific `Value` for a global + /// string, to hold the function name passed to LLVM intrinsic + /// `instrprof.increment()`. The `Value` is only created once per instance. + /// Multiple invocations with the same instance return the same `Value`. fn get_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value { if let Some(coverage_context) = self.coverage_context() { debug!("getting pgo_func_name_var for instance={:?}", instance); @@ -94,6 +104,54 @@ impl<'ll, 'tcx> CoverageInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { } impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { + fn add_coverage(&mut self, instance: Instance<'tcx>, coverage: &Coverage) { + let bx = self; + + let Coverage { kind, code_region } = coverage.clone(); + match kind { + CoverageKind::Counter { function_source_hash, id } => { + if bx.set_function_source_hash(instance, function_source_hash) { + // If `set_function_source_hash()` returned true, the coverage map is enabled, + // so continue adding the counter. + if let Some(code_region) = code_region { + // Note: Some counters do not have code regions, but may still be referenced + // from expressions. In that case, don't add the counter to the coverage map, + // but do inject the counter intrinsic. + bx.add_coverage_counter(instance, id, code_region); + } + + let coverageinfo = bx.tcx().coverageinfo(instance.def); + + let fn_name = bx.get_pgo_func_name_var(instance); + let hash = bx.const_u64(function_source_hash); + let num_counters = bx.const_u32(coverageinfo.num_counters); + let index = bx.const_u32(id.zero_based_index()); + debug!( + "codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})", + fn_name, hash, num_counters, index, + ); + bx.instrprof_increment(fn_name, hash, num_counters, index); + } + } + CoverageKind::Expression { id, lhs, op, rhs } => { + bx.add_coverage_counter_expression(instance, id, lhs, op, rhs, code_region); + } + CoverageKind::Unreachable => { + bx.add_coverage_unreachable( + instance, + code_region.expect("unreachable regions always have code regions"), + ); + } + } + } +} + +// These methods used to be part of trait `CoverageInfoBuilderMethods`, but +// after moving most coverage code out of SSA they are now just ordinary methods. +impl<'tcx> Builder<'_, '_, 'tcx> { + /// Returns true if the function source hash was added to the coverage map (even if it had + /// already been added, for this instance). Returns false *only* if `-C instrument-coverage` is + /// not enabled (a coverage map is not being generated). fn set_function_source_hash( &mut self, instance: Instance<'tcx>, @@ -115,6 +173,8 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { } } + /// Returns true if the counter was added to the coverage map; false if `-C instrument-coverage` + /// is not enabled (a coverage map is not being generated). fn add_coverage_counter( &mut self, instance: Instance<'tcx>, @@ -137,6 +197,8 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { } } + /// Returns true if the expression was added to the coverage map; false if + /// `-C instrument-coverage` is not enabled (a coverage map is not being generated). fn add_coverage_counter_expression( &mut self, instance: Instance<'tcx>, @@ -163,6 +225,8 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { } } + /// Returns true if the region was added to the coverage map; false if `-C instrument-coverage` + /// is not enabled (a coverage map is not being generated). fn add_coverage_unreachable(&mut self, instance: Instance<'tcx>, region: CodeRegion) -> bool { if let Some(coverage_context) = self.coverage_context() { debug!( @@ -199,8 +263,8 @@ fn declare_unused_fn<'tcx>(cx: &CodegenCx<'_, 'tcx>, def_id: DefId) -> Instance< tcx.symbol_name(instance).name, cx.fn_abi_of_fn_ptr( ty::Binder::dummy(tcx.mk_fn_sig( - [tcx.mk_unit()], - tcx.mk_unit(), + [Ty::new_unit(tcx)], + Ty::new_unit(tcx), false, hir::Unsafety::Unsafe, Abi::Rust, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 8be54b7eb71..37f30917609 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -38,6 +38,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global<'ll>(cx: &CodegenCx<'ll, ' unsafe { llvm::LLVMGetNamedGlobal(cx.llmod, c_section_var_name.as_ptr().cast()) }; section_var.unwrap_or_else(|| { + let section_name = b".debug_gdb_scripts\0"; let mut section_contents = Vec::new(); // Add the pretty printers for the standard library first. @@ -70,7 +71,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global<'ll>(cx: &CodegenCx<'ll, ' let section_var = cx .define_global(section_var_name, llvm_type) .unwrap_or_else(|| bug!("symbol `{}` is already defined", section_var_name)); - llvm::LLVMSetSection(section_var, c".debug_gdb_scripts".as_ptr().cast()); + llvm::LLVMSetSection(section_var, section_name.as_ptr().cast()); llvm::LLVMSetInitializer(section_var, cx.const_bytes(section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 4b88ab8a97a..d61400d3fa3 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -20,6 +20,7 @@ use crate::llvm::debuginfo::{ }; use crate::value::Value; +use cstr::cstr; use rustc_codegen_ssa::debuginfo::type_names::cpp_like_debuginfo; use rustc_codegen_ssa::debuginfo::type_names::VTableNameKind; use rustc_codegen_ssa::traits::*; @@ -167,7 +168,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( // a (fat) pointer. Make sure it is not called for e.g. `Box<T, NonZSTAllocator>`. debug_assert_eq!( cx.size_and_align_of(ptr_type), - cx.size_and_align_of(cx.tcx.mk_mut_ptr(pointee_type)) + cx.size_and_align_of(Ty::new_mut_ptr(cx.tcx, pointee_type)) ); let pointee_type_di_node = type_di_node(cx, pointee_type); @@ -222,8 +223,11 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( // at all and instead emit regular struct debuginfo for it. We just // need to make sure that we don't break existing debuginfo consumers // by doing that (at least not without a warning period). - let layout_type = - if ptr_type.is_box() { cx.tcx.mk_mut_ptr(pointee_type) } else { ptr_type }; + let layout_type = if ptr_type.is_box() { + Ty::new_mut_ptr(cx.tcx, pointee_type) + } else { + ptr_type + }; let layout = cx.layout_of(layout_type); let addr_field = layout.field(cx, abi::FAT_PTR_ADDR); @@ -811,6 +815,7 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>( let name_in_debuginfo = name_in_debuginfo.to_string_lossy(); let work_dir = tcx.sess.opts.working_dir.to_string_lossy(FileNameDisplayPreference::Remapped); + let flags = "\0"; let output_filenames = tcx.output_filenames(()); let split_name = if tcx.sess.target_can_use_split_dwarf() { output_filenames @@ -847,7 +852,7 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>( producer.as_ptr().cast(), producer.len(), tcx.sess.opts.optimize != config::OptLevel::No, - c"".as_ptr().cast(), + flags.as_ptr().cast(), 0, // NB: this doesn't actually have any perceptible effect, it seems. LLVM will instead // put the path supplied to `MCSplitDwarfFile` into the debug info of the final @@ -876,7 +881,8 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>( ); let val = llvm::LLVMMetadataAsValue(debug_context.llcontext, gcov_metadata); - llvm::LLVMAddNamedMetadataOperand(debug_context.llmod, c"llvm.gcov".as_ptr(), val); + let llvm_gcov_ident = cstr!("llvm.gcov"); + llvm::LLVMAddNamedMetadataOperand(debug_context.llmod, llvm_gcov_ident.as_ptr(), val); } // Insert `llvm.ident` metadata on the wasm targets since that will @@ -889,7 +895,7 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>( ); llvm::LLVMAddNamedMetadataOperand( debug_context.llmod, - c"llvm.ident".as_ptr(), + cstr!("llvm.ident").as_ptr(), llvm::LLVMMDNodeInContext(debug_context.llcontext, &name_metadata, 1), ); } @@ -1295,7 +1301,7 @@ fn build_vtable_type_di_node<'ll, 'tcx>( // All function pointers are described as opaque pointers. This could be improved in the future // by describing them as actual function pointers. - let void_pointer_ty = tcx.mk_imm_ptr(tcx.types.unit); + let void_pointer_ty = Ty::new_imm_ptr(tcx, tcx.types.unit); let void_pointer_type_di_node = type_di_node(cx, void_pointer_ty); let usize_di_node = type_di_node(cx, tcx.types.usize); let (pointer_size, pointer_align) = cx.size_and_align_of(void_pointer_ty); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index c2f16cad3fc..b924c771af7 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -113,7 +113,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { llvm::LLVMRustAddModuleFlag( self.llmod, llvm::LLVMModFlagBehavior::Warning, - c"Dwarf Version".as_ptr().cast(), + "Dwarf Version\0".as_ptr().cast(), dwarf_version, ); } else { @@ -121,16 +121,17 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { llvm::LLVMRustAddModuleFlag( self.llmod, llvm::LLVMModFlagBehavior::Warning, - c"CodeView".as_ptr().cast(), + "CodeView\0".as_ptr().cast(), 1, ) } // Prevent bitcode readers from deleting the debug info. + let ptr = "Debug Info Version\0".as_ptr(); llvm::LLVMRustAddModuleFlag( self.llmod, llvm::LLVMModFlagBehavior::Warning, - c"Debug Info Version".as_ptr().cast(), + ptr.cast(), llvm::LLVMRustDebugMetadataVersion(), ); } @@ -453,7 +454,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { ty::Array(ct, _) if (*ct == cx.tcx.types.u8) || cx.layout_of(*ct).is_zst() => { - cx.tcx.mk_imm_ptr(*ct) + Ty::new_imm_ptr(cx.tcx, *ct) } _ => t, }; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs index 6bcd3e5bf58..7be83638676 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs @@ -82,8 +82,8 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>( ty::Foreign(_) => { // Assert that pointers to foreign types really are thin: debug_assert_eq!( - cx.size_of(cx.tcx.mk_imm_ptr(pointee_tail_ty)), - cx.size_of(cx.tcx.mk_imm_ptr(cx.tcx.types.u8)) + cx.size_of(Ty::new_imm_ptr(cx.tcx, pointee_tail_ty)), + cx.size_of(Ty::new_imm_ptr(cx.tcx, cx.tcx.types.u8)) ); None } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 31bafa87814..a254c86c291 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -873,23 +873,29 @@ fn get_rust_try_fn<'ll, 'tcx>( // Define the type up front for the signature of the rust_try function. let tcx = cx.tcx; - let i8p = tcx.mk_mut_ptr(tcx.types.i8); + let i8p = Ty::new_mut_ptr(tcx, tcx.types.i8); // `unsafe fn(*mut i8) -> ()` - let try_fn_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig( - [i8p], - tcx.mk_unit(), - false, - hir::Unsafety::Unsafe, - Abi::Rust, - ))); + let try_fn_ty = Ty::new_fn_ptr( + tcx, + ty::Binder::dummy(tcx.mk_fn_sig( + [i8p], + Ty::new_unit(tcx), + false, + hir::Unsafety::Unsafe, + Abi::Rust, + )), + ); // `unsafe fn(*mut i8, *mut i8) -> ()` - let catch_fn_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig( - [i8p, i8p], - tcx.mk_unit(), - false, - hir::Unsafety::Unsafe, - Abi::Rust, - ))); + let catch_fn_ty = Ty::new_fn_ptr( + tcx, + ty::Binder::dummy(tcx.mk_fn_sig( + [i8p, i8p], + Ty::new_unit(tcx), + false, + hir::Unsafety::Unsafe, + Abi::Rust, + )), + ); // `unsafe fn(unsafe fn(*mut i8) -> (), *mut i8, unsafe fn(*mut i8, *mut i8) -> ()) -> i32` let rust_fn_sig = ty::Binder::dummy(cx.tcx.mk_fn_sig( [try_fn_ty, i8p, catch_fn_ty], diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 24968e00cc8..24ba28bbc82 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -11,7 +11,6 @@ #![feature(let_chains)] #![feature(never_type)] #![feature(impl_trait_in_assoc_type)] -#![feature(c_str_literals)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index b667bc4f6d4..3ad546b61e9 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1,7 +1,7 @@ #![allow(non_camel_case_types)] #![allow(non_upper_case_globals)] -use rustc_codegen_ssa::coverageinfo::map as coverage_map; +use crate::coverageinfo::map_data as coverage_map; use super::debuginfo::{ DIArray, DIBasicType, DIBuilder, DICompositeType, DIDerivedType, DIDescriptor, DIEnumerator, @@ -585,6 +585,16 @@ pub enum ThreadLocalMode { LocalExec, } +/// LLVMRustTailCallKind +#[derive(Copy, Clone)] +#[repr(C)] +pub enum TailCallKind { + None, + Tail, + MustTail, + NoTail, +} + /// LLVMRustChecksumKind #[derive(Copy, Clone)] #[repr(C)] @@ -1196,6 +1206,7 @@ extern "C" { NameLen: size_t, ) -> Option<&Value>; pub fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); + pub fn LLVMRustSetTailCallKind(CallInst: &Value, TKC: TailCallKind); // Operations on attributes pub fn LLVMRustCreateAttrNoValue(C: &Context, attr: AttributeKind) -> &Attribute; diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 3339e4e07ed..58e97be34f2 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -337,12 +337,13 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { // only wide pointer boxes are handled as pointers // thin pointer boxes with scalar allocators are handled by the general logic below ty::Adt(def, substs) if def.is_box() && cx.layout_of(substs.type_at(1)).is_zst() => { - let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty()); + let ptr_ty = Ty::new_mut_ptr(cx.tcx, self.ty.boxed_ty()); return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate); } // `dyn* Trait` has the same ABI as `*mut dyn Trait` ty::Dynamic(bounds, region, ty::DynStar) => { - let ptr_ty = cx.tcx.mk_mut_ptr(cx.tcx.mk_dynamic(bounds, region, ty::Dyn)); + let ptr_ty = + Ty::new_mut_ptr(cx.tcx, Ty::new_dynamic(cx.tcx, bounds, region, ty::Dyn)); return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate); } _ => {} diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index b19398e68c2..8800caa71d6 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -73,7 +73,7 @@ fn emit_ptr_va_arg<'ll, 'tcx>( let layout = bx.cx.layout_of(target_ty); let (llty, size, align) = if indirect { ( - bx.cx.layout_of(bx.cx.tcx.mk_imm_ptr(target_ty)).llvm_type(bx.cx), + bx.cx.layout_of(Ty::new_imm_ptr(bx.cx.tcx, target_ty)).llvm_type(bx.cx), bx.cx.data_layout().pointer_size, bx.cx.data_layout().pointer_align, ) diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index f8ced6949d5..9133601ecd1 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -199,7 +199,7 @@ fn vtable_ptr_ty<'tcx, Cx: CodegenMethods<'tcx>>( cx.scalar_pair_element_backend_type( cx.layout_of(match kind { // vtable is the second field of `*mut dyn Trait` - ty::Dyn => cx.tcx().mk_mut_ptr(target), + ty::Dyn => Ty::new_mut_ptr(cx.tcx(), target), // vtable is the second field of `dyn* Trait` ty::DynStar => target, }), diff --git a/compiler/rustc_codegen_ssa/src/coverageinfo/mod.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/mod.rs deleted file mode 100644 index 569fd3f1a51..00000000000 --- a/compiler/rustc_codegen_ssa/src/coverageinfo/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod ffi; -pub mod map; diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index c26a7422fdd..be4c81638d6 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -48,7 +48,6 @@ pub mod back; pub mod base; pub mod codegen_attrs; pub mod common; -pub mod coverageinfo; pub mod debuginfo; pub mod errors; pub mod glue; diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 93bed3a4a4a..9d1b3ce8266 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1505,9 +1505,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if let Some(slot) = self.personality_slot { slot } else { - let layout = cx.layout_of( - cx.tcx().mk_tup(&[cx.tcx().mk_mut_ptr(cx.tcx().types.u8), cx.tcx().types.i32]), - ); + let layout = cx.layout_of(Ty::new_tup( + cx.tcx(), + &[Ty::new_mut_ptr(cx.tcx(), cx.tcx().types.u8), cx.tcx().types.i32], + )); let slot = PlaceRef::alloca(bx, layout); self.personality_slot = Some(slot); slot diff --git a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs index f1fe495282a..ee70465966d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs @@ -1,13 +1,12 @@ use crate::traits::*; -use rustc_middle::mir::coverage::*; use rustc_middle::mir::Coverage; use rustc_middle::mir::SourceScope; use super::FunctionCx; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - pub fn codegen_coverage(&self, bx: &mut Bx, coverage: Coverage, scope: SourceScope) { + pub fn codegen_coverage(&self, bx: &mut Bx, coverage: &Coverage, scope: SourceScope) { // Determine the instance that coverage data was originally generated for. let instance = if let Some(inlined) = scope.inlined_instance(&self.mir.source_scopes) { self.monomorphize(inlined) @@ -15,41 +14,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.instance }; - let Coverage { kind, code_region } = coverage; - match kind { - CoverageKind::Counter { function_source_hash, id } => { - if bx.set_function_source_hash(instance, function_source_hash) { - // If `set_function_source_hash()` returned true, the coverage map is enabled, - // so continue adding the counter. - if let Some(code_region) = code_region { - // Note: Some counters do not have code regions, but may still be referenced - // from expressions. In that case, don't add the counter to the coverage map, - // but do inject the counter intrinsic. - bx.add_coverage_counter(instance, id, code_region); - } - - let coverageinfo = bx.tcx().coverageinfo(instance.def); - - let fn_name = bx.get_pgo_func_name_var(instance); - let hash = bx.const_u64(function_source_hash); - let num_counters = bx.const_u32(coverageinfo.num_counters); - let index = bx.const_u32(id.zero_based_index()); - debug!( - "codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})", - fn_name, hash, num_counters, index, - ); - bx.instrprof_increment(fn_name, hash, num_counters, index); - } - } - CoverageKind::Expression { id, lhs, op, rhs } => { - bx.add_coverage_counter_expression(instance, id, lhs, op, rhs, code_region); - } - CoverageKind::Unreachable => { - bx.add_coverage_unreachable( - instance, - code_region.expect("unreachable regions always have code regions"), - ); - } - } + // Handle the coverage info in a backend-specific way. + bx.add_coverage(instance, coverage); } } diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index c6589a40392..1ee89b3d5e8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -5,6 +5,7 @@ use rustc_middle::mir; use rustc_middle::ty; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; +use rustc_middle::ty::Ty; use rustc_session::config::DebugInfo; use rustc_span::symbol::{kw, Symbol}; use rustc_span::{BytePos, Span}; @@ -421,9 +422,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let create_alloca = |bx: &mut Bx, place: PlaceRef<'tcx, Bx::Value>, refcount| { // Create a variable which will be a pointer to the actual value - let ptr_ty = bx - .tcx() - .mk_ptr(ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: place.layout.ty }); + let ptr_ty = Ty::new_ptr( + bx.tcx(), + ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: place.layout.ty }, + ); let ptr_layout = bx.layout_of(ptr_ty); let alloca = PlaceRef::alloca(bx, ptr_layout); bx.set_var_name(alloca.llval, &format!("{}.ref{}.dbg.spill", var.name, refcount)); @@ -525,8 +527,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; for _ in 0..var.references { - var_ty = - bx.tcx().mk_ptr(ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: var_ty }); + var_ty = Ty::new_ptr( + bx.tcx(), + ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: var_ty }, + ); } self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span) diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index a58a61cd567..ab493ae5c1f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -61,7 +61,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { layout: TyAndLayout<'tcx>, ) -> Self { assert!(layout.is_unsized(), "tried to allocate indirect place for sized values"); - let ptr_ty = bx.cx().tcx().mk_mut_ptr(layout.ty); + let ptr_ty = Ty::new_mut_ptr(bx.cx().tcx(), layout.ty); let ptr_layout = bx.cx().layout_of(ptr_ty); Self::alloca(bx, ptr_layout) } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 2d3d0ec68b8..ab9eb421c5a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -581,7 +581,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::Ref(_, bk, place) => { let mk_ref = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| { - tcx.mk_ref( + Ty::new_ref( + tcx, tcx.lifetimes.re_erased, ty::TypeAndMut { ty, mutbl: bk.to_mutbl_lossy() }, ) @@ -592,7 +593,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::CopyForDeref(place) => self.codegen_operand(bx, &Operand::Copy(place)), mir::Rvalue::AddressOf(mutability, place) => { let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| { - tcx.mk_ptr(ty::TypeAndMut { ty, mutbl: mutability }) + Ty::new_ptr(tcx, ty::TypeAndMut { ty, mutbl: mutability }) }; self.codegen_place_to_pointer(bx, place, mk_ptr) } @@ -644,7 +645,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { lhs.layout.ty, ); let val_ty = op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty); - let operand_ty = bx.tcx().mk_tup(&[val_ty, bx.tcx().types.bool]); + let operand_ty = Ty::new_tup(bx.tcx(), &[val_ty, bx.tcx().types.bool]); OperandRef { val: result, layout: bx.cx().layout_of(operand_ty) } } @@ -734,7 +735,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let lloperand = operand.immediate(); let content_ty = self.monomorphize(content_ty); - let box_layout = bx.cx().layout_of(bx.tcx().mk_box(content_ty)); + let box_layout = bx.cx().layout_of(Ty::new_box(bx.tcx(), content_ty)); let llty_ptr = bx.cx().backend_type(box_layout); let val = bx.pointercast(lloperand, llty_ptr); diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index 314d364c0c2..899e41265bb 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -65,7 +65,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } mir::StatementKind::Coverage(box ref coverage) => { - self.codegen_coverage(bx, coverage.clone(), statement.source_info.scope); + self.codegen_coverage(bx, coverage, statement.source_info.scope); } mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op)) => { let op_val = self.codegen_operand(bx, op); diff --git a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs index e77201cf0c8..7e8de0ddc5b 100644 --- a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs @@ -1,57 +1,11 @@ use super::BackendTypes; -use rustc_hir::def_id::DefId; -use rustc_middle::mir::coverage::*; +use rustc_middle::mir::Coverage; use rustc_middle::ty::Instance; -pub trait CoverageInfoMethods<'tcx>: BackendTypes { - fn coverageinfo_finalize(&self); - - /// Codegen a small function that will never be called, with one counter - /// that will never be incremented, that gives LLVM coverage tools a - /// function definition it needs in order to resolve coverage map references - /// to unused functions. This is necessary so unused functions will appear - /// as uncovered (coverage execution count `0`) in LLVM coverage reports. - fn define_unused_fn(&self, def_id: DefId); - - /// For LLVM codegen, returns a function-specific `Value` for a global - /// string, to hold the function name passed to LLVM intrinsic - /// `instrprof.increment()`. The `Value` is only created once per instance. - /// Multiple invocations with the same instance return the same `Value`. - fn get_pgo_func_name_var(&self, instance: Instance<'tcx>) -> Self::Value; -} - pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes { - /// Returns true if the function source hash was added to the coverage map (even if it had - /// already been added, for this instance). Returns false *only* if `-C instrument-coverage` is - /// not enabled (a coverage map is not being generated). - fn set_function_source_hash( - &mut self, - instance: Instance<'tcx>, - function_source_hash: u64, - ) -> bool; - - /// Returns true if the counter was added to the coverage map; false if `-C instrument-coverage` - /// is not enabled (a coverage map is not being generated). - fn add_coverage_counter( - &mut self, - instance: Instance<'tcx>, - index: CounterValueReference, - region: CodeRegion, - ) -> bool; - - /// Returns true if the expression was added to the coverage map; false if - /// `-C instrument-coverage` is not enabled (a coverage map is not being generated). - fn add_coverage_counter_expression( - &mut self, - instance: Instance<'tcx>, - id: InjectedExpressionId, - lhs: ExpressionOperandId, - op: Op, - rhs: ExpressionOperandId, - region: Option<CodeRegion>, - ) -> bool; - - /// Returns true if the region was added to the coverage map; false if `-C instrument-coverage` - /// is not enabled (a coverage map is not being generated). - fn add_coverage_unreachable(&mut self, instance: Instance<'tcx>, region: CodeRegion) -> bool; + /// Handle the MIR coverage info in a backend-specific way. + /// + /// This can potentially be a no-op in backends that don't support + /// coverage instrumentation. + fn add_coverage(&mut self, instance: Instance<'tcx>, coverage: &Coverage); } diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index 782fdadbfb8..8cb58bd4c70 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -33,7 +33,7 @@ pub use self::asm::{AsmBuilderMethods, AsmMethods, GlobalAsmOperandRef, InlineAs pub use self::backend::{Backend, BackendTypes, CodegenBackend, ExtraBackendMethods}; pub use self::builder::{BuilderMethods, OverflowOp}; pub use self::consts::ConstMethods; -pub use self::coverageinfo::{CoverageInfoBuilderMethods, CoverageInfoMethods}; +pub use self::coverageinfo::CoverageInfoBuilderMethods; pub use self::debuginfo::{DebugInfoBuilderMethods, DebugInfoMethods}; pub use self::declare::PreDefineMethods; pub use self::intrinsic::IntrinsicCallMethods; @@ -59,7 +59,6 @@ pub trait CodegenMethods<'tcx>: + MiscMethods<'tcx> + ConstMethods<'tcx> + StaticMethods - + CoverageInfoMethods<'tcx> + DebugInfoMethods<'tcx> + AsmMethods<'tcx> + PreDefineMethods<'tcx> @@ -75,7 +74,6 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where + MiscMethods<'tcx> + ConstMethods<'tcx> + StaticMethods - + CoverageInfoMethods<'tcx> + DebugInfoMethods<'tcx> + AsmMethods<'tcx> + PreDefineMethods<'tcx> diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 5cc1fa2a497..a3064b53db1 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -1,12 +1,10 @@ // Not in interpret to make sure we do not use private implementation details use crate::errors::MaxNumNodesInConstErr; -use crate::interpret::{ - intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, Scalar, -}; +use crate::interpret::{intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, Scalar}; use rustc_middle::mir; use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; mod error; @@ -87,23 +85,24 @@ pub(crate) fn eval_to_valtree<'tcx>( } #[instrument(skip(tcx), level = "debug")] -pub(crate) fn try_destructure_mir_constant<'tcx>( +pub(crate) fn try_destructure_mir_constant_for_diagnostics<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - val: mir::ConstantKind<'tcx>, -) -> InterpResult<'tcx, mir::DestructuredConstant<'tcx>> { + val: ConstValue<'tcx>, + ty: Ty<'tcx>, +) -> Option<mir::DestructuredConstant<'tcx>> { + let param_env = ty::ParamEnv::reveal_all(); let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessStatics::No); - let op = ecx.eval_mir_constant(&val, None, None)?; + let op = ecx.const_val_to_op(val, ty, None).ok()?; // We go to `usize` as we cannot allocate anything bigger anyway. - let (field_count, variant, down) = match val.ty().kind() { + let (field_count, variant, down) = match ty.kind() { ty::Array(_, len) => (len.eval_target_usize(tcx, param_env) as usize, None, op), ty::Adt(def, _) if def.variants().is_empty() => { - throw_ub!(Unreachable) + return None; } ty::Adt(def, _) => { - let variant = ecx.read_discriminant(&op)?.1; - let down = ecx.operand_downcast(&op, variant)?; + let variant = ecx.read_discriminant(&op).ok()?.1; + let down = ecx.operand_downcast(&op, variant).ok()?; (def.variants()[variant].fields.len(), Some(variant), down) } ty::Tuple(substs) => (substs.len(), None, op), @@ -112,12 +111,12 @@ pub(crate) fn try_destructure_mir_constant<'tcx>( let fields_iter = (0..field_count) .map(|i| { - let field_op = ecx.operand_field(&down, i)?; + let field_op = ecx.operand_field(&down, i).ok()?; let val = op_to_const(&ecx, &field_op); - Ok(mir::ConstantKind::Val(val, field_op.layout.ty)) + Some((val, field_op.layout.ty)) }) - .collect::<InterpResult<'tcx, Vec<_>>>()?; + .collect::<Option<Vec<_>>>()?; let fields = tcx.arena.alloc_from_iter(fields_iter); - Ok(mir::DestructuredConstant { variant, fields }) + Some(mir::DestructuredConstant { variant, fields }) } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 4f10e4837ce..ed64a7655b5 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -170,7 +170,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::pref_align_of | sym::variant_count => self.tcx.types.usize, sym::needs_drop => self.tcx.types.bool, sym::type_id => self.tcx.types.u128, - sym::type_name => self.tcx.mk_static_str(), + sym::type_name => Ty::new_static_str(self.tcx.tcx), _ => bug!(), }; let val = self.ctfe_query(None, |tcx| { diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index e30af165501..5f89d652fab 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -106,7 +106,7 @@ impl<Prov: Provenance> std::fmt::Display for ImmTy<'_, Prov> { // Just print the ptr value. `pretty_print_const_scalar_ptr` would also try to // print what is points to, which would fail since it has no access to the local // memory. - cx.pretty_print_const_pointer(ptr, ty, true) + cx.pretty_print_const_pointer(ptr, ty) } } } @@ -633,7 +633,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - pub(super) fn const_val_to_op( + pub(crate) fn const_val_to_op( &self, val_val: ConstValue<'tcx>, ty: Ty<'tcx>, diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 7bca7efdf5a..e04764636cc 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -22,7 +22,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> InterpResult<'tcx> { let (val, overflowed, ty) = self.overflowing_binary_op(op, &left, &right)?; debug_assert_eq!( - self.tcx.mk_tup(&[ty, self.tcx.types.bool]), + Ty::new_tup(self.tcx.tcx, &[ty, self.tcx.types.bool]), dest.layout.ty, "type mismatch for result of {:?}", op, diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 2a31a59ad6c..24c1fe43d0c 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -9,6 +9,7 @@ use rustc_index::IndexSlice; use rustc_middle::mir; use rustc_middle::ty; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; +use rustc_middle::ty::Ty; use rustc_target::abi::{self, Abi, Align, FieldIdx, HasDataLayout, Size, FIRST_VARIANT}; use super::{ @@ -395,7 +396,7 @@ where // (Transmuting is okay since this is an in-memory place. We also double-check the size // stays the same.) let (len, e_ty) = mplace.layout.ty.simd_size_and_type(*self.tcx); - let array = self.tcx.mk_array(e_ty, len); + let array = Ty::new_array(self.tcx.tcx, e_ty, len); let layout = self.layout_of(array)?; assert_eq!(layout.size, mplace.layout.size); Ok((MPlaceTy { layout, ..*mplace }, len)) @@ -775,7 +776,8 @@ where let meta = Scalar::from_target_usize(u64::try_from(str.len()).unwrap(), self); let mplace = MemPlace { ptr: ptr.into(), meta: MemPlaceMeta::Meta(meta) }; - let ty = self.tcx.mk_ref( + let ty = Ty::new_ref( + self.tcx.tcx, self.tcx.lifetimes.re_static, ty::TypeAndMut { ty: self.tcx.types.str_, mutbl }, ); diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 91da930db4f..d7d31fe1887 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -12,6 +12,7 @@ use either::{Left, Right}; use rustc_middle::mir; use rustc_middle::ty; use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::Ty; use rustc_target::abi::{self, Abi, VariantIdx}; use super::{ @@ -317,7 +318,9 @@ where let (meta, ty) = match base.layout.ty.kind() { // It is not nice to match on the type, but that seems to be the only way to // implement this. - ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(*inner, inner_len)), + ty::Array(inner, _) => { + (MemPlaceMeta::None, Ty::new_array(self.tcx.tcx, *inner, inner_len)) + } ty::Slice(..) => { let len = Scalar::from_target_usize(inner_len, self); (MemPlaceMeta::Meta(len), base.layout.ty) diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 719d8a14b41..15823a5975e 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -650,7 +650,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Adjust receiver argument. Layout can be any (thin) ptr. args[0] = ImmTy::from_immediate( Scalar::from_maybe_pointer(adjusted_receiver, self).into(), - self.layout_of(self.tcx.mk_mut_ptr(dyn_ty))?, + self.layout_of(Ty::new_mut_ptr(self.tcx.tcx, dyn_ty))?, ) .into(); trace!("Patched receiver operand to {:#?}", args[0]); @@ -703,7 +703,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let arg = ImmTy::from_immediate( place.to_ref(self), - self.layout_of(self.tcx.mk_mut_ptr(place.layout.ty))?, + self.layout_of(Ty::new_mut_ptr(self.tcx.tcx, place.layout.ty))?, ); let ret = MPlaceTy::fake_alloc_zst(self.layout_of(self.tcx.types.unit)?); diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 8314f53ba57..c126f749bf3 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -52,10 +52,8 @@ pub fn provide(providers: &mut Providers) { let (param_env, raw) = param_env_and_value.into_parts(); const_eval::eval_to_valtree(tcx, param_env, raw) }; - providers.try_destructure_mir_constant = |tcx, param_env_and_value| { - let (param_env, value) = param_env_and_value.into_parts(); - const_eval::try_destructure_mir_constant(tcx, param_env, value).ok() - }; + providers.try_destructure_mir_constant_for_diagnostics = + |tcx, (cv, ty)| const_eval::try_destructure_mir_constant_for_diagnostics(tcx, cv, ty); providers.valtree_to_const_val = |tcx, (ty, valtree)| { const_eval::valtree_to_const_value(tcx, ty::ParamEnv::empty().and(ty), valtree) }; diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 36c76e53231..015a4aa94cd 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -223,7 +223,7 @@ impl Qualif for CustomEq { def: AdtDef<'tcx>, substs: SubstsRef<'tcx>, ) -> bool { - let ty = cx.tcx.mk_adt(def, substs); + let ty = Ty::new_adt(cx.tcx, def, substs); !ty.is_structural_eq_shallow(cx.tcx) } } diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index dd80f745c2f..1b39a76e460 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -17,7 +17,7 @@ use rustc_middle::mir; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::subst::InternalSubsts; -use rustc_middle::ty::{self, List, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, List, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::Span; use rustc_index::{Idx, IndexSlice, IndexVec}; @@ -867,7 +867,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let ty = local_decls[place.local].ty; let span = statement.source_info.span; - let ref_ty = tcx.mk_ref( + let ref_ty = Ty::new_ref( + tcx, tcx.lifetimes.re_erased, ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() }, ); diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 7ed73a3f6fe..2a6c341b662 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -67,8 +67,8 @@ impl<'tcx> MirPass<'tcx> for Validator { unwind_edge_count: 0, reachable_blocks: traversal::reachable_as_bitset(body), storage_liveness, - place_cache: Vec::new(), - value_cache: Vec::new(), + place_cache: FxHashSet::default(), + value_cache: FxHashSet::default(), }; checker.visit_body(body); checker.check_cleanup_control_flow(); @@ -95,8 +95,8 @@ struct TypeChecker<'a, 'tcx> { unwind_edge_count: usize, reachable_blocks: BitSet<BasicBlock>, storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive<'static>>, - place_cache: Vec<PlaceRef<'tcx>>, - value_cache: Vec<u128>, + place_cache: FxHashSet<PlaceRef<'tcx>>, + value_cache: FxHashSet<u128>, } impl<'a, 'tcx> TypeChecker<'a, 'tcx> { @@ -951,10 +951,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.value_cache.clear(); self.value_cache.extend(targets.iter().map(|(value, _)| value)); - let all_len = self.value_cache.len(); - self.value_cache.sort_unstable(); - self.value_cache.dedup(); - let has_duplicates = all_len != self.value_cache.len(); + let has_duplicates = targets.iter().len() != self.value_cache.len(); if has_duplicates { self.fail( location, @@ -987,16 +984,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // passed by a reference to the callee. Consequently they must be non-overlapping. // Currently this simply checks for duplicate places. self.place_cache.clear(); - self.place_cache.push(destination.as_ref()); + self.place_cache.insert(destination.as_ref()); + let mut has_duplicates = false; for arg in args { if let Operand::Move(place) = arg { - self.place_cache.push(place.as_ref()); + has_duplicates |= !self.place_cache.insert(place.as_ref()); } } - let all_len = self.place_cache.len(); - let mut dedup = FxHashSet::default(); - self.place_cache.retain(|p| dedup.insert(*p)); - let has_duplicates = all_len != self.place_cache.len(); + if has_duplicates { self.fail( location, diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 78f73d193e3..a5c3cb3f857 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -10,7 +10,7 @@ arrayvec = { version = "0.7", default-features = false } bitflags = "1.2.1" cfg-if = "1.0" ena = "0.14.2" -indexmap = { version = "1.9.3" } +indexmap = { version = "2.0.0" } jobserver_crate = { version = "0.1.13", package = "jobserver" } libc = "0.2" measureme = "10.0.0" diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 4b4573ec2eb..9352fe3147e 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -24,6 +24,7 @@ use rustc_data_structures::profiling::{ }; use rustc_data_structures::sync::SeqCst; use rustc_errors::registry::{InvalidErrorCode, Registry}; +use rustc_errors::{markdown, ColorConfig}; use rustc_errors::{ DiagnosticMessage, ErrorGuaranteed, Handler, PResult, SubdiagnosticMessage, TerminalUrl, }; @@ -282,7 +283,7 @@ fn run_compiler( interface::set_thread_safe_mode(&sopts.unstable_opts); if let Some(ref code) = matches.opt_str("explain") { - handle_explain(&early_error_handler, diagnostics_registry(), code); + handle_explain(&early_error_handler, diagnostics_registry(), code, sopts.color); return Ok(()); } @@ -540,7 +541,7 @@ impl Compilation { } } -fn handle_explain(handler: &EarlyErrorHandler, registry: Registry, code: &str) { +fn handle_explain(handler: &EarlyErrorHandler, registry: Registry, code: &str, color: ColorConfig) { let upper_cased_code = code.to_ascii_uppercase(); let normalised = if upper_cased_code.starts_with('E') { upper_cased_code } else { format!("E{code:0>4}") }; @@ -564,7 +565,7 @@ fn handle_explain(handler: &EarlyErrorHandler, registry: Registry, code: &str) { text.push('\n'); } if io::stdout().is_terminal() { - show_content_with_pager(&text); + show_md_content_with_pager(&text, color); } else { safe_print!("{text}"); } @@ -575,34 +576,72 @@ fn handle_explain(handler: &EarlyErrorHandler, registry: Registry, code: &str) { } } -fn show_content_with_pager(content: &str) { +/// If color is always or auto, print formatted & colorized markdown. If color is never or +/// if formatted printing fails, print the raw text. +/// +/// Prefers a pager, falls back standard print +fn show_md_content_with_pager(content: &str, color: ColorConfig) { + let mut fallback_to_println = false; let pager_name = env::var_os("PAGER").unwrap_or_else(|| { if cfg!(windows) { OsString::from("more.com") } else { OsString::from("less") } }); - let mut fallback_to_println = false; + let mut cmd = Command::new(&pager_name); + // FIXME: find if other pagers accept color options + let mut print_formatted = if pager_name == "less" { + cmd.arg("-r"); + true + } else if ["bat", "catbat", "delta"].iter().any(|v| *v == pager_name) { + true + } else { + false + }; - match Command::new(pager_name).stdin(Stdio::piped()).spawn() { - Ok(mut pager) => { - if let Some(pipe) = pager.stdin.as_mut() { - if pipe.write_all(content.as_bytes()).is_err() { - fallback_to_println = true; - } - } + if color == ColorConfig::Never { + print_formatted = false; + } else if color == ColorConfig::Always { + print_formatted = true; + } + + let mdstream = markdown::MdStream::parse_str(content); + let bufwtr = markdown::create_stdout_bufwtr(); + let mut mdbuf = bufwtr.buffer(); + if mdstream.write_termcolor_buf(&mut mdbuf).is_err() { + print_formatted = false; + } - if pager.wait().is_err() { + if let Ok(mut pager) = cmd.stdin(Stdio::piped()).spawn() { + if let Some(pipe) = pager.stdin.as_mut() { + let res = if print_formatted { + pipe.write_all(mdbuf.as_slice()) + } else { + pipe.write_all(content.as_bytes()) + }; + + if res.is_err() { fallback_to_println = true; } } - Err(_) => { + + if pager.wait().is_err() { fallback_to_println = true; } + } else { + fallback_to_println = true; } // If pager fails for whatever reason, we should still print the content // to standard output if fallback_to_println { - safe_print!("{content}"); + let fmt_success = match color { + ColorConfig::Auto => io::stdout().is_terminal() && bufwtr.print(&mdbuf).is_ok(), + ColorConfig::Always => bufwtr.print(&mdbuf).is_ok(), + ColorConfig::Never => false, + }; + + if !fmt_success { + safe_print!("{content}"); + } } } diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index bd3033fcb3e..e8bcd7c1184 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -20,7 +20,7 @@ rustc_hir = { path = "../rustc_hir" } rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_type_ir = { path = "../rustc_type_ir" } unicode-width = "0.1.4" -termcolor = "1.0" +termcolor = "1.2.0" annotate-snippets = "0.9" termize = "0.1.1" serde = { version = "1.0.125", features = [ "derive" ] } diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index d8c997b49a1..9d4d159fd96 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -616,7 +616,7 @@ pub enum ColorConfig { } impl ColorConfig { - fn to_color_choice(self) -> ColorChoice { + pub fn to_color_choice(self) -> ColorChoice { match self { ColorConfig::Always => { if io::stderr().is_terminal() { diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 24d1cc8af82..b9db25103a3 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -61,6 +61,7 @@ pub mod emitter; pub mod error; pub mod json; mod lock; +pub mod markdown; pub mod registry; mod snippet; mod styled_buffer; diff --git a/compiler/rustc_errors/src/markdown/mod.rs b/compiler/rustc_errors/src/markdown/mod.rs new file mode 100644 index 00000000000..53b766dfcce --- /dev/null +++ b/compiler/rustc_errors/src/markdown/mod.rs @@ -0,0 +1,76 @@ +//! A simple markdown parser that can write formatted text to the terminal +//! +//! Entrypoint is `MdStream::parse_str(...)` +use std::io; + +use termcolor::{Buffer, BufferWriter, ColorChoice}; +mod parse; +mod term; + +/// An AST representation of a Markdown document +#[derive(Clone, Debug, Default, PartialEq)] +pub struct MdStream<'a>(Vec<MdTree<'a>>); + +impl<'a> MdStream<'a> { + /// Parse a markdown string to a tokenstream + #[must_use] + pub fn parse_str(s: &str) -> MdStream<'_> { + parse::entrypoint(s) + } + + /// Write formatted output to a termcolor buffer + pub fn write_termcolor_buf(&self, buf: &mut Buffer) -> io::Result<()> { + term::entrypoint(self, buf) + } +} + +/// Create a termcolor buffer with the `Always` color choice +pub fn create_stdout_bufwtr() -> BufferWriter { + BufferWriter::stdout(ColorChoice::Always) +} + +/// A single tokentree within a Markdown document +#[derive(Clone, Debug, PartialEq)] +pub enum MdTree<'a> { + /// Leaf types + Comment(&'a str), + CodeBlock { + txt: &'a str, + lang: Option<&'a str>, + }, + CodeInline(&'a str), + Strong(&'a str), + Emphasis(&'a str), + Strikethrough(&'a str), + PlainText(&'a str), + /// [Foo](www.foo.com) or simple anchor <www.foo.com> + Link { + disp: &'a str, + link: &'a str, + }, + /// `[Foo link][ref]` + RefLink { + disp: &'a str, + id: Option<&'a str>, + }, + /// [ref]: www.foo.com + LinkDef { + id: &'a str, + link: &'a str, + }, + /// Break bewtween two paragraphs (double `\n`), not directly parsed but + /// added later + ParagraphBreak, + /// Break bewtween two lines (single `\n`) + LineBreak, + HorizontalRule, + Heading(u8, MdStream<'a>), + OrderedListItem(u16, MdStream<'a>), + UnorderedListItem(MdStream<'a>), +} + +impl<'a> From<Vec<MdTree<'a>>> for MdStream<'a> { + fn from(value: Vec<MdTree<'a>>) -> Self { + Self(value) + } +} diff --git a/compiler/rustc_errors/src/markdown/parse.rs b/compiler/rustc_errors/src/markdown/parse.rs new file mode 100644 index 00000000000..362a451fde6 --- /dev/null +++ b/compiler/rustc_errors/src/markdown/parse.rs @@ -0,0 +1,588 @@ +use crate::markdown::{MdStream, MdTree}; +use std::{iter, mem, str}; + +/// Short aliases that we can use in match patterns. If an end pattern is not +/// included, this type may be variable +const ANC_E: &[u8] = b">"; +const ANC_S: &[u8] = b"<"; +const BRK: &[u8] = b"---"; +const CBK: &[u8] = b"```"; +const CIL: &[u8] = b"`"; +const CMT_E: &[u8] = b"-->"; +const CMT_S: &[u8] = b"<!--"; +const EMP: &[u8] = b"_"; +const HDG: &[u8] = b"#"; +const LNK_CHARS: &str = "$-_.+!*'()/&?=:%"; +const LNK_E: &[u8] = b"]"; +const LNK_S: &[u8] = b"["; +const STG: &[u8] = b"**"; +const STK: &[u8] = b"~~"; +const UL1: &[u8] = b"* "; +const UL2: &[u8] = b"- "; + +/// Pattern replacements +const REPLACEMENTS: &[(&str, &str)] = &[ + ("(c)", "©"), + ("(C)", "©"), + ("(r)", "®"), + ("(R)", "®"), + ("(tm)", "â„¢"), + ("(TM)", "â„¢"), + (":crab:", "🦀"), + ("\n", " "), +]; + +/// `(extracted, remaining)` +type Parsed<'a> = (MdTree<'a>, &'a [u8]); +/// Output of a parse function +type ParseResult<'a> = Option<Parsed<'a>>; + +/// Parsing context +#[derive(Clone, Copy, Debug, PartialEq)] +struct Context { + /// If true, we are at a the topmost level (not recursing a nested tt) + top_block: bool, + /// Previous character + prev: Prev, +} + +/// Character class preceding this one +#[derive(Clone, Copy, Debug, PartialEq)] +enum Prev { + Newline, + /// Whitespace that is not a newline + Whitespace, + Escape, + Any, +} + +impl Default for Context { + /// Most common setting for non top-level parsing: not top block, not at + /// line start (yes leading whitespace, not escaped) + fn default() -> Self { + Self { top_block: false, prev: Prev::Whitespace } + } +} + +/// Flags to simple parser function +#[derive(Clone, Copy, Debug, PartialEq)] +enum ParseOpt { + /// Ignore escapes before closing pattern, trim content + TrimNoEsc, + None, +} + +/// Parse a buffer +pub fn entrypoint(txt: &str) -> MdStream<'_> { + let ctx = Context { top_block: true, prev: Prev::Newline }; + normalize(parse_recursive(txt.trim().as_bytes(), ctx), &mut Vec::new()) +} + +/// Parse a buffer with specified context +fn parse_recursive<'a>(buf: &'a [u8], ctx: Context) -> MdStream<'_> { + use ParseOpt as Po; + use Prev::{Escape, Newline, Whitespace}; + + let mut stream: Vec<MdTree<'a>> = Vec::new(); + let Context { top_block: top_blk, mut prev } = ctx; + + // wip_buf is our entire unprocessed (unpushed) buffer, loop_buf is our to + // check buffer that shrinks with each loop + let mut wip_buf = buf; + let mut loop_buf = wip_buf; + + while !loop_buf.is_empty() { + let next_prev = match loop_buf[0] { + b'\n' => Newline, + b'\\' => Escape, + x if x.is_ascii_whitespace() => Whitespace, + _ => Prev::Any, + }; + + let res: ParseResult<'_> = match (top_blk, prev) { + (_, Newline | Whitespace) if loop_buf.starts_with(CMT_S) => { + parse_simple_pat(loop_buf, CMT_S, CMT_E, Po::TrimNoEsc, MdTree::Comment) + } + (true, Newline) if loop_buf.starts_with(CBK) => Some(parse_codeblock(loop_buf)), + (_, Newline | Whitespace) if loop_buf.starts_with(CIL) => parse_codeinline(loop_buf), + (true, Newline | Whitespace) if loop_buf.starts_with(HDG) => parse_heading(loop_buf), + (true, Newline) if loop_buf.starts_with(BRK) => { + Some((MdTree::HorizontalRule, parse_to_newline(loop_buf).1)) + } + (_, Newline | Whitespace) if loop_buf.starts_with(EMP) => { + parse_simple_pat(loop_buf, EMP, EMP, Po::None, MdTree::Emphasis) + } + (_, Newline | Whitespace) if loop_buf.starts_with(STG) => { + parse_simple_pat(loop_buf, STG, STG, Po::None, MdTree::Strong) + } + (_, Newline | Whitespace) if loop_buf.starts_with(STK) => { + parse_simple_pat(loop_buf, STK, STK, Po::None, MdTree::Strikethrough) + } + (_, Newline | Whitespace) if loop_buf.starts_with(ANC_S) => { + let tt_fn = |link| MdTree::Link { disp: link, link }; + let ret = parse_simple_pat(loop_buf, ANC_S, ANC_E, Po::None, tt_fn); + match ret { + Some((MdTree::Link { disp, .. }, _)) + if disp.chars().all(|ch| LNK_CHARS.contains(ch)) => + { + ret + } + _ => None, + } + } + (_, Newline) if (loop_buf.starts_with(UL1) || loop_buf.starts_with(UL2)) => { + Some(parse_unordered_li(loop_buf)) + } + (_, Newline) if ord_list_start(loop_buf).is_some() => Some(parse_ordered_li(loop_buf)), + (_, Newline | Whitespace) if loop_buf.starts_with(LNK_S) => { + parse_any_link(loop_buf, top_blk && prev == Prev::Newline) + } + (_, Escape | _) => None, + }; + + if let Some((tree, rest)) = res { + // We found something: push our WIP and then push the found tree + let prev_buf = &wip_buf[..(wip_buf.len() - loop_buf.len())]; + if !prev_buf.is_empty() { + let prev_str = str::from_utf8(prev_buf).unwrap(); + stream.push(MdTree::PlainText(prev_str)); + } + stream.push(tree); + + wip_buf = rest; + loop_buf = rest; + } else { + // Just move on to the next character + loop_buf = &loop_buf[1..]; + // If we are at the end and haven't found anything, just push plain text + if loop_buf.is_empty() && !wip_buf.is_empty() { + let final_str = str::from_utf8(wip_buf).unwrap(); + stream.push(MdTree::PlainText(final_str)); + } + }; + + prev = next_prev; + } + + MdStream(stream) +} + +/// The simplest kind of patterns: data within start and end patterns +fn parse_simple_pat<'a, F>( + buf: &'a [u8], + start_pat: &[u8], + end_pat: &[u8], + opts: ParseOpt, + create_tt: F, +) -> ParseResult<'a> +where + F: FnOnce(&'a str) -> MdTree<'a>, +{ + let ignore_esc = matches!(opts, ParseOpt::TrimNoEsc); + let trim = matches!(opts, ParseOpt::TrimNoEsc); + let (txt, rest) = parse_with_end_pat(&buf[start_pat.len()..], end_pat, ignore_esc)?; + let mut txt = str::from_utf8(txt).unwrap(); + if trim { + txt = txt.trim(); + } + Some((create_tt(txt), rest)) +} + +/// Parse backtick-wrapped inline code. Accounts for >1 backtick sets +fn parse_codeinline(buf: &[u8]) -> ParseResult<'_> { + let seps = buf.iter().take_while(|ch| **ch == b'`').count(); + let (txt, rest) = parse_with_end_pat(&buf[seps..], &buf[..seps], true)?; + Some((MdTree::CodeInline(str::from_utf8(txt).unwrap()), rest)) +} + +/// Parse a codeblock. Accounts for >3 backticks and language specification +fn parse_codeblock(buf: &[u8]) -> Parsed<'_> { + // account for ````code```` style + let seps = buf.iter().take_while(|ch| **ch == b'`').count(); + let end_sep = &buf[..seps]; + let mut working = &buf[seps..]; + + // Handle "````rust" style language specifications + let next_ws_idx = working.iter().take_while(|ch| !ch.is_ascii_whitespace()).count(); + + let lang = if next_ws_idx > 0 { + // Munch the lang + let tmp = str::from_utf8(&working[..next_ws_idx]).unwrap(); + working = &working[next_ws_idx..]; + Some(tmp) + } else { + None + }; + + let mut end_pat = vec![b'\n']; + end_pat.extend(end_sep); + + // Find first end pattern with nothing else on its line + let mut found = None; + for idx in (0..working.len()).filter(|idx| working[*idx..].starts_with(&end_pat)) { + let (eol_txt, rest) = parse_to_newline(&working[(idx + end_pat.len())..]); + if !eol_txt.iter().any(u8::is_ascii_whitespace) { + found = Some((&working[..idx], rest)); + break; + } + } + + let (txt, rest) = found.unwrap_or((working, &[])); + let txt = str::from_utf8(txt).unwrap().trim_matches('\n'); + + (MdTree::CodeBlock { txt, lang }, rest) +} + +fn parse_heading(buf: &[u8]) -> ParseResult<'_> { + let level = buf.iter().take_while(|ch| **ch == b'#').count(); + let buf = &buf[level..]; + + if level > 6 || (buf.len() > 1 && !buf[0].is_ascii_whitespace()) { + // Enforce max 6 levels and whitespace following the `##` pattern + return None; + } + + let (txt, rest) = parse_to_newline(&buf[1..]); + let ctx = Context { top_block: false, prev: Prev::Whitespace }; + let stream = parse_recursive(txt, ctx); + + Some((MdTree::Heading(level.try_into().unwrap(), stream), rest)) +} + +/// Bulleted list +fn parse_unordered_li(buf: &[u8]) -> Parsed<'_> { + debug_assert!(buf.starts_with(b"* ") || buf.starts_with(b"- ")); + let (txt, rest) = get_indented_section(&buf[2..]); + let ctx = Context { top_block: false, prev: Prev::Whitespace }; + let stream = parse_recursive(trim_ascii_start(txt), ctx); + (MdTree::UnorderedListItem(stream), rest) +} + +/// Numbered list +fn parse_ordered_li(buf: &[u8]) -> Parsed<'_> { + let (num, pos) = ord_list_start(buf).unwrap(); // success tested in caller + let (txt, rest) = get_indented_section(&buf[pos..]); + let ctx = Context { top_block: false, prev: Prev::Whitespace }; + let stream = parse_recursive(trim_ascii_start(txt), ctx); + (MdTree::OrderedListItem(num, stream), rest) +} + +/// Find first line that isn't empty or doesn't start with whitespace, that will +/// be our contents +fn get_indented_section(buf: &[u8]) -> (&[u8], &[u8]) { + let mut end = buf.len(); + for (idx, window) in buf.windows(2).enumerate() { + let &[ch, next_ch] = window else {unreachable!("always 2 elements")}; + if idx >= buf.len().saturating_sub(2) && next_ch == b'\n' { + // End of stream + end = buf.len().saturating_sub(1); + break; + } else if ch == b'\n' && (!next_ch.is_ascii_whitespace() || next_ch == b'\n') { + end = idx; + break; + } + } + + (&buf[..end], &buf[end..]) +} + +/// Verify a valid ordered list start (e.g. `1.`) and parse it. Returns the +/// parsed number and offset of character after the dot. +fn ord_list_start(buf: &[u8]) -> Option<(u16, usize)> { + let pos = buf.iter().take(10).position(|ch| *ch == b'.')?; + let n = str::from_utf8(&buf[..pos]).ok()?; + if !buf.get(pos + 1)?.is_ascii_whitespace() { + return None; + } + n.parse::<u16>().ok().map(|v| (v, pos + 2)) +} + +/// Parse links. `can_be_def` indicates that a link definition is possible (top +/// level, located at the start of a line) +fn parse_any_link(buf: &[u8], can_be_def: bool) -> ParseResult<'_> { + let (bracketed, rest) = parse_with_end_pat(&buf[1..], LNK_E, true)?; + if rest.is_empty() { + return None; + } + + let disp = str::from_utf8(bracketed).unwrap(); + match (can_be_def, rest[0]) { + (true, b':') => { + let (link, tmp) = parse_to_newline(&rest[1..]); + let link = str::from_utf8(link).unwrap().trim(); + Some((MdTree::LinkDef { id: disp, link }, tmp)) + } + (_, b'(') => parse_simple_pat(rest, b"(", b")", ParseOpt::TrimNoEsc, |link| MdTree::Link { + disp, + link, + }), + (_, b'[') => parse_simple_pat(rest, b"[", b"]", ParseOpt::TrimNoEsc, |id| { + MdTree::RefLink { disp, id: Some(id) } + }), + _ => Some((MdTree::RefLink { disp, id: None }, rest)), + } +} + +/// Find and consume an end pattern, return `(match, residual)` +fn parse_with_end_pat<'a>( + buf: &'a [u8], + end_sep: &[u8], + ignore_esc: bool, +) -> Option<(&'a [u8], &'a [u8])> { + // Find positions that start with the end seperator + for idx in (0..buf.len()).filter(|idx| buf[*idx..].starts_with(end_sep)) { + if !ignore_esc && idx > 0 && buf[idx - 1] == b'\\' { + continue; + } + return Some((&buf[..idx], &buf[idx + end_sep.len()..])); + } + None +} + +/// Resturn `(match, residual)` to end of line. The EOL is returned with the +/// residual. +fn parse_to_newline(buf: &[u8]) -> (&[u8], &[u8]) { + buf.iter().position(|ch| *ch == b'\n').map_or((buf, &[]), |pos| buf.split_at(pos)) +} + +/// Take a parsed stream and fix the little things +fn normalize<'a>(MdStream(stream): MdStream<'a>, linkdefs: &mut Vec<MdTree<'a>>) -> MdStream<'a> { + let mut new_stream = Vec::with_capacity(stream.len()); + let new_defs = stream.iter().filter(|tt| matches!(tt, MdTree::LinkDef { .. })); + linkdefs.extend(new_defs.cloned()); + + // Run plaintest expansions on types that need it, call this function on nested types + for item in stream { + match item { + MdTree::PlainText(txt) => expand_plaintext(txt, &mut new_stream, MdTree::PlainText), + MdTree::Strong(txt) => expand_plaintext(txt, &mut new_stream, MdTree::Strong), + MdTree::Emphasis(txt) => expand_plaintext(txt, &mut new_stream, MdTree::Emphasis), + MdTree::Strikethrough(txt) => { + expand_plaintext(txt, &mut new_stream, MdTree::Strikethrough); + } + MdTree::RefLink { disp, id } => new_stream.push(match_reflink(linkdefs, disp, id)), + MdTree::OrderedListItem(n, st) => { + new_stream.push(MdTree::OrderedListItem(n, normalize(st, linkdefs))); + } + MdTree::UnorderedListItem(st) => { + new_stream.push(MdTree::UnorderedListItem(normalize(st, linkdefs))); + } + MdTree::Heading(n, st) => new_stream.push(MdTree::Heading(n, normalize(st, linkdefs))), + _ => new_stream.push(item), + } + } + + // Remove non printing types, duplicate paragraph breaks, and breaks at start/end + new_stream.retain(|x| !matches!(x, MdTree::Comment(_) | MdTree::LinkDef { .. })); + new_stream.dedup_by(|r, l| matches!((r, l), (MdTree::ParagraphBreak, MdTree::ParagraphBreak))); + + if new_stream.first().is_some_and(is_break_ty) { + new_stream.remove(0); + } + if new_stream.last().is_some_and(is_break_ty) { + new_stream.pop(); + } + + // Remove paragraph breaks that shouldn't be there. w[1] is what will be + // removed in these cases. Note that these are the items to keep, not delete + // (for `retain`) + let to_keep: Vec<bool> = new_stream + .windows(3) + .map(|w| { + !((matches!(&w[1], MdTree::ParagraphBreak) + && matches!(should_break(&w[0], &w[2]), BreakRule::Always(1) | BreakRule::Never)) + || (matches!(&w[1], MdTree::PlainText(txt) if txt.trim().is_empty()) + && matches!( + should_break(&w[0], &w[2]), + BreakRule::Always(_) | BreakRule::Never + ))) + }) + .collect(); + let mut iter = iter::once(true).chain(to_keep).chain(iter::once(true)); + new_stream.retain(|_| iter.next().unwrap()); + + // Insert line or paragraph breaks where there should be some + let mut insertions = 0; + let to_insert: Vec<(usize, MdTree<'_>)> = new_stream + .windows(2) + .enumerate() + .filter_map(|(idx, w)| match should_break(&w[0], &w[1]) { + BreakRule::Always(1) => Some((idx, MdTree::LineBreak)), + BreakRule::Always(2) => Some((idx, MdTree::ParagraphBreak)), + _ => None, + }) + .map(|(idx, tt)| { + insertions += 1; + (idx + insertions, tt) + }) + .collect(); + to_insert.into_iter().for_each(|(idx, tt)| new_stream.insert(idx, tt)); + + MdStream(new_stream) +} + +/// Whether two types should or shouldn't have a paragraph break between them +#[derive(Clone, Copy, Debug, PartialEq)] +enum BreakRule { + Always(u8), + Never, + Optional, +} + +/// Blocks that automatically handle their own text wrapping +fn should_break(left: &MdTree<'_>, right: &MdTree<'_>) -> BreakRule { + use MdTree::*; + + match (left, right) { + // Separate these types with a single line + (HorizontalRule, _) + | (_, HorizontalRule) + | (OrderedListItem(_, _), OrderedListItem(_, _)) + | (UnorderedListItem(_), UnorderedListItem(_)) => BreakRule::Always(1), + // Condensed types shouldn't have an extra break on either side + (Comment(_) | ParagraphBreak | Heading(_, _), _) | (_, Comment(_) | ParagraphBreak) => { + BreakRule::Never + } + // Block types should always be separated by full breaks + (CodeBlock { .. } | OrderedListItem(_, _) | UnorderedListItem(_), _) + | (_, CodeBlock { .. } | Heading(_, _) | OrderedListItem(_, _) | UnorderedListItem(_)) => { + BreakRule::Always(2) + } + // Text types may or may not be separated by a break + ( + CodeInline(_) + | Strong(_) + | Emphasis(_) + | Strikethrough(_) + | PlainText(_) + | Link { .. } + | RefLink { .. } + | LinkDef { .. }, + CodeInline(_) + | Strong(_) + | Emphasis(_) + | Strikethrough(_) + | PlainText(_) + | Link { .. } + | RefLink { .. } + | LinkDef { .. }, + ) => BreakRule::Optional, + (LineBreak, _) | (_, LineBreak) => { + unreachable!("should have been removed during deduplication") + } + } +} + +/// Types that indicate some form of break +fn is_break_ty(val: &MdTree<'_>) -> bool { + matches!(val, MdTree::ParagraphBreak | MdTree::LineBreak) + // >1 break between paragraphs acts as a break + || matches!(val, MdTree::PlainText(txt) if txt.trim().is_empty()) +} + +/// Perform tranformations to text. This splits paragraphs, replaces patterns, +/// and corrects newlines. +/// +/// To avoid allocating strings (and using a different heavier tt type), our +/// replace method means split into three and append each. For this reason, any +/// viewer should treat consecutive `PlainText` types as belonging to the same +/// paragraph. +fn expand_plaintext<'a>( + txt: &'a str, + stream: &mut Vec<MdTree<'a>>, + mut f: fn(&'a str) -> MdTree<'a>, +) { + if txt.is_empty() { + return; + } else if txt == "\n" { + if let Some(tt) = stream.last() { + let tmp = MdTree::PlainText(" "); + if should_break(tt, &tmp) == BreakRule::Optional { + stream.push(tmp); + } + } + return; + } + let mut queue1 = Vec::new(); + let mut queue2 = Vec::new(); + let stream_start_len = stream.len(); + for paragraph in txt.split("\n\n") { + if paragraph.is_empty() { + stream.push(MdTree::ParagraphBreak); + continue; + } + let paragraph = trim_extra_ws(paragraph); + + queue1.clear(); + queue1.push(paragraph); + + for (from, to) in REPLACEMENTS { + queue2.clear(); + for item in &queue1 { + for s in item.split(from) { + queue2.extend(&[s, to]); + } + if queue2.len() > 1 { + let _ = queue2.pop(); // remove last unnecessary intersperse + } + } + mem::swap(&mut queue1, &mut queue2); + } + + // Make sure we don't double whitespace + queue1.retain(|s| !s.is_empty()); + for idx in 0..queue1.len() { + queue1[idx] = trim_extra_ws(queue1[idx]); + if idx < queue1.len() - 1 + && queue1[idx].ends_with(char::is_whitespace) + && queue1[idx + 1].starts_with(char::is_whitespace) + { + queue1[idx] = queue1[idx].trim_end(); + } + } + stream.extend(queue1.iter().copied().filter(|txt| !txt.is_empty()).map(&mut f)); + stream.push(MdTree::ParagraphBreak); + } + + if stream.len() - stream_start_len > 1 { + let _ = stream.pop(); // remove last unnecessary intersperse + } +} + +/// Turn reflinks (links with reference IDs) into normal standalone links using +/// listed link definitions +fn match_reflink<'a>(linkdefs: &[MdTree<'a>], disp: &'a str, match_id: Option<&str>) -> MdTree<'a> { + let to_match = match_id.unwrap_or(disp); // Match with the display name if there isn't an id + for def in linkdefs { + if let MdTree::LinkDef { id, link } = def { + if *id == to_match { + return MdTree::Link { disp, link }; + } + } + } + MdTree::Link { disp, link: "" } // link not found +} + +/// If there is more than one whitespace char at start or end, trim the extras +fn trim_extra_ws(mut txt: &str) -> &str { + let start_ws = + txt.bytes().position(|ch| !ch.is_ascii_whitespace()).unwrap_or(txt.len()).saturating_sub(1); + txt = &txt[start_ws..]; + let end_ws = txt + .bytes() + .rev() + .position(|ch| !ch.is_ascii_whitespace()) + .unwrap_or(txt.len()) + .saturating_sub(1); + &txt[..txt.len() - end_ws] +} + +/// If there is more than one whitespace char at start, trim the extras +fn trim_ascii_start(buf: &[u8]) -> &[u8] { + let count = buf.iter().take_while(|ch| ch.is_ascii_whitespace()).count(); + &buf[count..] +} + +#[cfg(test)] +#[path = "tests/parse.rs"] +mod tests; diff --git a/compiler/rustc_errors/src/markdown/term.rs b/compiler/rustc_errors/src/markdown/term.rs new file mode 100644 index 00000000000..e45ba6d2cda --- /dev/null +++ b/compiler/rustc_errors/src/markdown/term.rs @@ -0,0 +1,189 @@ +use std::cell::Cell; +use std::io::{self, Write}; + +use termcolor::{Buffer, Color, ColorSpec, WriteColor}; + +use crate::markdown::{MdStream, MdTree}; + +const DEFAULT_COLUMN_WIDTH: usize = 140; + +thread_local! { + /// Track the position of viewable characters in our buffer + static CURSOR: Cell<usize> = Cell::new(0); + /// Width of the terminal + static WIDTH: Cell<usize> = Cell::new(DEFAULT_COLUMN_WIDTH); +} + +/// Print to terminal output to a buffer +pub fn entrypoint(stream: &MdStream<'_>, buf: &mut Buffer) -> io::Result<()> { + #[cfg(not(test))] + if let Some((w, _)) = termize::dimensions() { + WIDTH.with(|c| c.set(std::cmp::min(w, DEFAULT_COLUMN_WIDTH))); + } + write_stream(stream, buf, None, 0)?; + buf.write_all(b"\n") +} + +/// Write the buffer, reset to the default style after each +fn write_stream( + MdStream(stream): &MdStream<'_>, + buf: &mut Buffer, + default: Option<&ColorSpec>, + indent: usize, +) -> io::Result<()> { + match default { + Some(c) => buf.set_color(c)?, + None => buf.reset()?, + } + + for tt in stream { + write_tt(tt, buf, indent)?; + if let Some(c) = default { + buf.set_color(c)?; + } + } + + buf.reset()?; + Ok(()) +} + +pub fn write_tt(tt: &MdTree<'_>, buf: &mut Buffer, indent: usize) -> io::Result<()> { + match tt { + MdTree::CodeBlock { txt, lang: _ } => { + buf.set_color(ColorSpec::new().set_dimmed(true))?; + buf.write_all(txt.as_bytes())?; + } + MdTree::CodeInline(txt) => { + buf.set_color(ColorSpec::new().set_dimmed(true))?; + write_wrapping(buf, txt, indent, None)?; + } + MdTree::Strong(txt) => { + buf.set_color(ColorSpec::new().set_bold(true))?; + write_wrapping(buf, txt, indent, None)?; + } + MdTree::Emphasis(txt) => { + buf.set_color(ColorSpec::new().set_italic(true))?; + write_wrapping(buf, txt, indent, None)?; + } + MdTree::Strikethrough(txt) => { + buf.set_color(ColorSpec::new().set_strikethrough(true))?; + write_wrapping(buf, txt, indent, None)?; + } + MdTree::PlainText(txt) => { + write_wrapping(buf, txt, indent, None)?; + } + MdTree::Link { disp, link } => { + write_wrapping(buf, disp, indent, Some(link))?; + } + MdTree::ParagraphBreak => { + buf.write_all(b"\n\n")?; + reset_cursor(); + } + MdTree::LineBreak => { + buf.write_all(b"\n")?; + reset_cursor(); + } + MdTree::HorizontalRule => { + (0..WIDTH.with(Cell::get)).for_each(|_| buf.write_all(b"-").unwrap()); + reset_cursor(); + } + MdTree::Heading(n, stream) => { + let mut cs = ColorSpec::new(); + cs.set_fg(Some(Color::Cyan)); + match n { + 1 => cs.set_intense(true).set_bold(true).set_underline(true), + 2 => cs.set_intense(true).set_underline(true), + 3 => cs.set_intense(true).set_italic(true), + 4.. => cs.set_underline(true).set_italic(true), + 0 => unreachable!(), + }; + write_stream(stream, buf, Some(&cs), 0)?; + buf.write_all(b"\n")?; + } + MdTree::OrderedListItem(n, stream) => { + let base = format!("{n}. "); + write_wrapping(buf, &format!("{base:<4}"), indent, None)?; + write_stream(stream, buf, None, indent + 4)?; + } + MdTree::UnorderedListItem(stream) => { + let base = "* "; + write_wrapping(buf, &format!("{base:<4}"), indent, None)?; + write_stream(stream, buf, None, indent + 4)?; + } + // Patterns popped in previous step + MdTree::Comment(_) | MdTree::LinkDef { .. } | MdTree::RefLink { .. } => unreachable!(), + } + + buf.reset()?; + + Ok(()) +} + +/// End of that block, just wrap the line +fn reset_cursor() { + CURSOR.with(|cur| cur.set(0)); +} + +/// Change to be generic on Write for testing. If we have a link URL, we don't +/// count the extra tokens to make it clickable. +fn write_wrapping<B: io::Write>( + buf: &mut B, + text: &str, + indent: usize, + link_url: Option<&str>, +) -> io::Result<()> { + let ind_ws = &b" "[..indent]; + let mut to_write = text; + if let Some(url) = link_url { + // This is a nonprinting prefix so we don't increment our cursor + write!(buf, "\x1b]8;;{url}\x1b\\")?; + } + CURSOR.with(|cur| { + loop { + if cur.get() == 0 { + buf.write_all(ind_ws)?; + cur.set(indent); + } + let ch_count = WIDTH.with(Cell::get) - cur.get(); + let mut iter = to_write.char_indices(); + let Some((end_idx, _ch)) = iter.nth(ch_count) else { + // Write entire line + buf.write_all(to_write.as_bytes())?; + cur.set(cur.get()+to_write.chars().count()); + break; + }; + + if let Some((break_idx, ch)) = to_write[..end_idx] + .char_indices() + .rev() + .find(|(_idx, ch)| ch.is_whitespace() || ['_', '-'].contains(ch)) + { + // Found whitespace to break at + if ch.is_whitespace() { + writeln!(buf, "{}", &to_write[..break_idx])?; + to_write = to_write[break_idx..].trim_start(); + } else { + // Break at a `-` or `_` separator + writeln!(buf, "{}", &to_write.get(..break_idx + 1).unwrap_or(to_write))?; + to_write = to_write.get(break_idx + 1..).unwrap_or_default().trim_start(); + } + } else { + // No whitespace, we need to just split + let ws_idx = + iter.find(|(_, ch)| ch.is_whitespace()).map_or(to_write.len(), |(idx, _)| idx); + writeln!(buf, "{}", &to_write[..ws_idx])?; + to_write = to_write.get(ws_idx + 1..).map_or("", str::trim_start); + } + cur.set(0); + } + if link_url.is_some() { + buf.write_all(b"\x1b]8;;\x1b\\")?; + } + + Ok(()) + }) +} + +#[cfg(test)] +#[path = "tests/term.rs"] +mod tests; diff --git a/compiler/rustc_errors/src/markdown/tests/input.md b/compiler/rustc_errors/src/markdown/tests/input.md new file mode 100644 index 00000000000..7d207fc4220 --- /dev/null +++ b/compiler/rustc_errors/src/markdown/tests/input.md @@ -0,0 +1,50 @@ +# H1 Heading [with a link][remote-link] + +H1 content: **some words in bold** and `so does inline code` + +## H2 Heading + +H2 content: _some words in italic_ + +### H3 Heading + +H3 content: ~~strikethrough~~ text + +#### H4 Heading + +H4 content: A [simple link](https://docs.rs) and a [remote-link]. + +--- + +A section break was above. We can also do paragraph breaks: + +(new paragraph) and unordered lists: + +- Item 1 in `code` +- Item 2 in _italics_ + +Or ordered: + +1. Item 1 in **bold** +2. Item 2 with some long lines that should wrap: Lorem ipsum dolor sit amet, + consectetur adipiscing elit. Aenean ac mattis nunc. Phasellus elit quam, + pulvinar ac risus in, dictum vehicula turpis. Vestibulum neque est, accumsan + in cursus sit amet, dictum a nunc. Suspendisse aliquet, lorem eu eleifend + accumsan, magna neque sodales nisi, a aliquet lectus leo eu sem. + +--- + +## Code + +Both `inline code` and code blocks are supported: + +```rust +/// A rust enum +#[derive(Debug, PartialEq, Clone)] +enum Foo { + /// Start of line + Bar +} +``` + +[remote-link]: http://docs.rs diff --git a/compiler/rustc_errors/src/markdown/tests/output.stdout b/compiler/rustc_errors/src/markdown/tests/output.stdout new file mode 100644 index 00000000000..23c60d5c319 --- /dev/null +++ b/compiler/rustc_errors/src/markdown/tests/output.stdout @@ -0,0 +1,35 @@ +[0m[0m[1m[4m[38;5;14mH1 Heading [0m[0m[1m[4m[38;5;14m]8;;http://docs.rs\with a link]8;;\[0m[0m[1m[4m[38;5;14m[0m +[0mH1 content: [0m[0m[1msome words in bold[0m and [0m[0m[2mso does inline code[0m + +[0m[0m[4m[38;5;14mH2 Heading[0m[0m[4m[38;5;14m[0m +[0mH2 content: [0m[0m[3msome words in italic[0m + +[0m[0m[3m[38;5;14mH3 Heading[0m[0m[3m[38;5;14m[0m +[0mH3 content: [0m[0m[9mstrikethrough[0m text[0m + +[0m[0m[3m[4m[36mH4 Heading[0m[0m[3m[4m[36m[0m +[0mH4 content: A [0m]8;;https://docs.rs\simple link]8;;\[0m and a [0m]8;;http://docs.rs\remote-link]8;;\[0m.[0m +[0m--------------------------------------------------------------------------------------------------------------------------------------------[0m +[0mA section break was above. We can also do paragraph breaks:[0m + +[0m(new paragraph) and unordered lists:[0m + +[0m* [0mItem 1 in [0m[0m[2mcode[0m[0m[0m +[0m* [0mItem 2 in [0m[0m[3mitalics[0m[0m[0m + +[0mOr ordered:[0m + +[0m1. [0mItem 1 in [0m[0m[1mbold[0m[0m[0m +[0m2. [0mItem 2 with some long lines that should wrap: Lorem ipsum dolor sit amet,[0m consectetur adipiscing elit. Aenean ac mattis nunc. Phasellus + elit quam,[0m pulvinar ac risus in, dictum vehicula turpis. Vestibulum neque est, accumsan[0m in cursus sit amet, dictum a nunc. Suspendisse + aliquet, lorem eu eleifend[0m accumsan, magna neque sodales nisi, a aliquet lectus leo eu sem.[0m[0m[0m +[0m--------------------------------------------------------------------------------------------------------------------------------------------[0m +[0m[0m[4m[38;5;14mCode[0m[0m[4m[38;5;14m[0m +[0mBoth [0m[0m[2minline code[0m and code blocks are supported:[0m + +[0m[0m[2m/// A rust enum +#[derive(Debug, PartialEq, Clone)] +enum Foo { + /// Start of line + Bar +}[0m[0m diff --git a/compiler/rustc_errors/src/markdown/tests/parse.rs b/compiler/rustc_errors/src/markdown/tests/parse.rs new file mode 100644 index 00000000000..e39e8c89b35 --- /dev/null +++ b/compiler/rustc_errors/src/markdown/tests/parse.rs @@ -0,0 +1,312 @@ +use super::*; +use ParseOpt as PO; + +#[test] +fn test_parse_simple() { + let buf = "**abcd** rest"; + let (t, r) = parse_simple_pat(buf.as_bytes(), STG, STG, PO::None, MdTree::Strong).unwrap(); + assert_eq!(t, MdTree::Strong("abcd")); + assert_eq!(r, b" rest"); + + // Escaping should fail + let buf = r"**abcd\** rest"; + let res = parse_simple_pat(buf.as_bytes(), STG, STG, PO::None, MdTree::Strong); + assert!(res.is_none()); +} + +#[test] +fn test_parse_comment() { + let opt = PO::TrimNoEsc; + let buf = "<!-- foobar! -->rest"; + let (t, r) = parse_simple_pat(buf.as_bytes(), CMT_S, CMT_E, opt, MdTree::Comment).unwrap(); + assert_eq!(t, MdTree::Comment("foobar!")); + assert_eq!(r, b"rest"); + + let buf = r"<!-- foobar! \-->rest"; + let (t, r) = parse_simple_pat(buf.as_bytes(), CMT_S, CMT_E, opt, MdTree::Comment).unwrap(); + assert_eq!(t, MdTree::Comment(r"foobar! \")); + assert_eq!(r, b"rest"); +} + +#[test] +fn test_parse_heading() { + let buf1 = "# Top level\nrest"; + let (t, r) = parse_heading(buf1.as_bytes()).unwrap(); + assert_eq!(t, MdTree::Heading(1, vec![MdTree::PlainText("Top level")].into())); + assert_eq!(r, b"\nrest"); + + let buf1 = "# Empty"; + let (t, r) = parse_heading(buf1.as_bytes()).unwrap(); + assert_eq!(t, MdTree::Heading(1, vec![MdTree::PlainText("Empty")].into())); + assert_eq!(r, b""); + + // Combo + let buf2 = "### Top `level` _woo_\nrest"; + let (t, r) = parse_heading(buf2.as_bytes()).unwrap(); + assert_eq!( + t, + MdTree::Heading( + 3, + vec![ + MdTree::PlainText("Top "), + MdTree::CodeInline("level"), + MdTree::PlainText(" "), + MdTree::Emphasis("woo"), + ] + .into() + ) + ); + assert_eq!(r, b"\nrest"); +} + +#[test] +fn test_parse_code_inline() { + let buf1 = "`abcd` rest"; + let (t, r) = parse_codeinline(buf1.as_bytes()).unwrap(); + assert_eq!(t, MdTree::CodeInline("abcd")); + assert_eq!(r, b" rest"); + + // extra backticks, newline + let buf2 = "```ab\ncd``` rest"; + let (t, r) = parse_codeinline(buf2.as_bytes()).unwrap(); + assert_eq!(t, MdTree::CodeInline("ab\ncd")); + assert_eq!(r, b" rest"); + + // test no escaping + let buf3 = r"`abcd\` rest"; + let (t, r) = parse_codeinline(buf3.as_bytes()).unwrap(); + assert_eq!(t, MdTree::CodeInline(r"abcd\")); + assert_eq!(r, b" rest"); +} + +#[test] +fn test_parse_code_block() { + let buf1 = "```rust\ncode\ncode\n```\nleftovers"; + let (t, r) = parse_codeblock(buf1.as_bytes()); + assert_eq!(t, MdTree::CodeBlock { txt: "code\ncode", lang: Some("rust") }); + assert_eq!(r, b"\nleftovers"); + + let buf2 = "`````\ncode\ncode````\n`````\nleftovers"; + let (t, r) = parse_codeblock(buf2.as_bytes()); + assert_eq!(t, MdTree::CodeBlock { txt: "code\ncode````", lang: None }); + assert_eq!(r, b"\nleftovers"); +} + +#[test] +fn test_parse_link() { + let simple = "[see here](docs.rs) other"; + let (t, r) = parse_any_link(simple.as_bytes(), false).unwrap(); + assert_eq!(t, MdTree::Link { disp: "see here", link: "docs.rs" }); + assert_eq!(r, b" other"); + + let simple_toplevel = "[see here](docs.rs) other"; + let (t, r) = parse_any_link(simple_toplevel.as_bytes(), true).unwrap(); + assert_eq!(t, MdTree::Link { disp: "see here", link: "docs.rs" }); + assert_eq!(r, b" other"); + + let reference = "[see here] other"; + let (t, r) = parse_any_link(reference.as_bytes(), true).unwrap(); + assert_eq!(t, MdTree::RefLink { disp: "see here", id: None }); + assert_eq!(r, b" other"); + + let reference_full = "[see here][docs-rs] other"; + let (t, r) = parse_any_link(reference_full.as_bytes(), false).unwrap(); + assert_eq!(t, MdTree::RefLink { disp: "see here", id: Some("docs-rs") }); + assert_eq!(r, b" other"); + + let reference_def = "[see here]: docs.rs\nother"; + let (t, r) = parse_any_link(reference_def.as_bytes(), true).unwrap(); + assert_eq!(t, MdTree::LinkDef { id: "see here", link: "docs.rs" }); + assert_eq!(r, b"\nother"); +} + +const IND1: &str = r"test standard + ind + ind2 +not ind"; +const IND2: &str = r"test end of stream + 1 + 2 +"; +const IND3: &str = r"test empty lines + 1 + 2 + +not ind"; + +#[test] +fn test_indented_section() { + let (t, r) = get_indented_section(IND1.as_bytes()); + assert_eq!(str::from_utf8(t).unwrap(), "test standard\n ind\n ind2"); + assert_eq!(str::from_utf8(r).unwrap(), "\nnot ind"); + + let (txt, rest) = get_indented_section(IND2.as_bytes()); + assert_eq!(str::from_utf8(txt).unwrap(), "test end of stream\n 1\n 2"); + assert_eq!(str::from_utf8(rest).unwrap(), "\n"); + + let (txt, rest) = get_indented_section(IND3.as_bytes()); + assert_eq!(str::from_utf8(txt).unwrap(), "test empty lines\n 1\n 2"); + assert_eq!(str::from_utf8(rest).unwrap(), "\n\nnot ind"); +} + +const HBT: &str = r"# Heading + +content"; + +#[test] +fn test_heading_breaks() { + let expected = vec![ + MdTree::Heading(1, vec![MdTree::PlainText("Heading")].into()), + MdTree::PlainText("content"), + ] + .into(); + let res = entrypoint(HBT); + assert_eq!(res, expected); +} + +const NL1: &str = r"start + +end"; +const NL2: &str = r"start + + +end"; +const NL3: &str = r"start + + + +end"; + +#[test] +fn test_newline_breaks() { + let expected = + vec![MdTree::PlainText("start"), MdTree::ParagraphBreak, MdTree::PlainText("end")].into(); + for (idx, check) in [NL1, NL2, NL3].iter().enumerate() { + let res = entrypoint(check); + assert_eq!(res, expected, "failed {idx}"); + } +} + +const WRAP: &str = "plain _italics +italics_"; + +#[test] +fn test_wrap_pattern() { + let expected = vec![ + MdTree::PlainText("plain "), + MdTree::Emphasis("italics"), + MdTree::Emphasis(" "), + MdTree::Emphasis("italics"), + ] + .into(); + let res = entrypoint(WRAP); + assert_eq!(res, expected); +} + +const WRAP_NOTXT: &str = r"_italics_ +**bold**"; + +#[test] +fn test_wrap_notxt() { + let expected = + vec![MdTree::Emphasis("italics"), MdTree::PlainText(" "), MdTree::Strong("bold")].into(); + let res = entrypoint(WRAP_NOTXT); + assert_eq!(res, expected); +} + +const MIXED_LIST: &str = r"start +- _italics item_ +<!-- comment --> +- **bold item** + second line [link1](foobar1) + third line [link2][link-foo] +- :crab: + extra indent +end +[link-foo]: foobar2 +"; + +#[test] +fn test_list() { + let expected = vec![ + MdTree::PlainText("start"), + MdTree::ParagraphBreak, + MdTree::UnorderedListItem(vec![MdTree::Emphasis("italics item")].into()), + MdTree::LineBreak, + MdTree::UnorderedListItem( + vec![ + MdTree::Strong("bold item"), + MdTree::PlainText(" second line "), + MdTree::Link { disp: "link1", link: "foobar1" }, + MdTree::PlainText(" third line "), + MdTree::Link { disp: "link2", link: "foobar2" }, + ] + .into(), + ), + MdTree::LineBreak, + MdTree::UnorderedListItem( + vec![MdTree::PlainText("🦀"), MdTree::PlainText(" extra indent")].into(), + ), + MdTree::ParagraphBreak, + MdTree::PlainText("end"), + ] + .into(); + let res = entrypoint(MIXED_LIST); + assert_eq!(res, expected); +} + +const SMOOSHED: &str = r#" +start +### heading +1. ordered item +```rust +println!("Hello, world!"); +``` +`inline` +``end`` +"#; + +#[test] +fn test_without_breaks() { + let expected = vec![ + MdTree::PlainText("start"), + MdTree::ParagraphBreak, + MdTree::Heading(3, vec![MdTree::PlainText("heading")].into()), + MdTree::OrderedListItem(1, vec![MdTree::PlainText("ordered item")].into()), + MdTree::ParagraphBreak, + MdTree::CodeBlock { txt: r#"println!("Hello, world!");"#, lang: Some("rust") }, + MdTree::ParagraphBreak, + MdTree::CodeInline("inline"), + MdTree::PlainText(" "), + MdTree::CodeInline("end"), + ] + .into(); + let res = entrypoint(SMOOSHED); + assert_eq!(res, expected); +} + +const CODE_STARTLINE: &str = r#" +start +`code` +middle +`more code` +end +"#; + +#[test] +fn test_code_at_start() { + let expected = vec![ + MdTree::PlainText("start"), + MdTree::PlainText(" "), + MdTree::CodeInline("code"), + MdTree::PlainText(" "), + MdTree::PlainText("middle"), + MdTree::PlainText(" "), + MdTree::CodeInline("more code"), + MdTree::PlainText(" "), + MdTree::PlainText("end"), + ] + .into(); + let res = entrypoint(CODE_STARTLINE); + assert_eq!(res, expected); +} diff --git a/compiler/rustc_errors/src/markdown/tests/term.rs b/compiler/rustc_errors/src/markdown/tests/term.rs new file mode 100644 index 00000000000..3b31c6d6295 --- /dev/null +++ b/compiler/rustc_errors/src/markdown/tests/term.rs @@ -0,0 +1,90 @@ +use std::io::BufWriter; +use std::path::PathBuf; +use termcolor::{BufferWriter, ColorChoice}; + +use super::*; +use crate::markdown::MdStream; + +const INPUT: &str = include_str!("input.md"); +const OUTPUT_PATH: &[&str] = &[env!("CARGO_MANIFEST_DIR"), "src","markdown","tests","output.stdout"]; + +const TEST_WIDTH: usize = 80; + +// We try to make some words long to create corner cases +const TXT: &str = r"Lorem ipsum dolor sit amet, consecteturadipiscingelit. +Fusce-id-urna-sollicitudin, pharetra nisl nec, lobortis tellus. In at +metus hendrerit, tincidunteratvel, ultrices turpis. Curabitur_risus_sapien, +porta-sed-nunc-sed, ultricesposuerelacus. Sed porttitor quis +dolor non venenatis. Aliquam ut. "; + +const WRAPPED: &str = r"Lorem ipsum dolor sit amet, consecteturadipiscingelit. Fusce-id-urna- +sollicitudin, pharetra nisl nec, lobortis tellus. In at metus hendrerit, +tincidunteratvel, ultrices turpis. Curabitur_risus_sapien, porta-sed-nunc-sed, +ultricesposuerelacus. Sed porttitor quis dolor non venenatis. Aliquam ut. Lorem + ipsum dolor sit amet, consecteturadipiscingelit. Fusce-id-urna- + sollicitudin, pharetra nisl nec, lobortis tellus. In at metus hendrerit, + tincidunteratvel, ultrices turpis. Curabitur_risus_sapien, porta-sed-nunc- + sed, ultricesposuerelacus. Sed porttitor quis dolor non venenatis. Aliquam + ut. Sample link lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, +consecteturadipiscingelit. Fusce-id-urna-sollicitudin, pharetra nisl nec, +lobortis tellus. In at metus hendrerit, tincidunteratvel, ultrices turpis. +Curabitur_risus_sapien, porta-sed-nunc-sed, ultricesposuerelacus. Sed porttitor +quis dolor non venenatis. Aliquam ut. "; + +#[test] +fn test_wrapping_write() { + WIDTH.with(|w| w.set(TEST_WIDTH)); + let mut buf = BufWriter::new(Vec::new()); + let txt = TXT.replace("-\n","-").replace("_\n","_").replace('\n', " ").replace(" ", ""); + write_wrapping(&mut buf, &txt, 0, None).unwrap(); + write_wrapping(&mut buf, &txt, 4, None).unwrap(); + write_wrapping( + &mut buf, + "Sample link lorem ipsum dolor sit amet. ", + 4, + Some("link-address-placeholder"), + ) + .unwrap(); + write_wrapping(&mut buf, &txt, 0, None).unwrap(); + let out = String::from_utf8(buf.into_inner().unwrap()).unwrap(); + let out = out + .replace("\x1b\\", "") + .replace('\x1b', "") + .replace("]8;;", "") + .replace("link-address-placeholder", ""); + + for line in out.lines() { + assert!(line.len() <= TEST_WIDTH, "line length\n'{line}'") + } + + assert_eq!(out, WRAPPED); +} + +#[test] +fn test_output() { + // Capture `--bless` when run via ./x + let bless = std::env::var("RUSTC_BLESS").unwrap_or_default() == "1"; + let ast = MdStream::parse_str(INPUT); + let bufwtr = BufferWriter::stderr(ColorChoice::Always); + let mut buffer = bufwtr.buffer(); + ast.write_termcolor_buf(&mut buffer).unwrap(); + + let mut blessed = PathBuf::new(); + blessed.extend(OUTPUT_PATH); + + if bless { + std::fs::write(&blessed, buffer.into_inner()).unwrap(); + eprintln!("blessed output at {}", blessed.display()); + } else { + let output = buffer.into_inner(); + if std::fs::read(blessed).unwrap() != output { + // hack: I don't know any way to write bytes to the captured stdout + // that cargo test uses + let mut out = std::io::stdout(); + out.write_all(b"\n\nMarkdown output did not match. Expected:\n").unwrap(); + out.write_all(&output).unwrap(); + out.write_all(b"\n\n").unwrap(); + panic!("markdown output mismatch"); + } + } +} diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 906c31c9a3d..5185820a727 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -391,6 +391,8 @@ declare_features! ( (active, doc_masked, "1.21.0", Some(44027), None), /// Allows `dyn* Trait` objects. (incomplete, dyn_star, "1.65.0", Some(102425), None), + // Uses generic effect parameters for ~const bounds + (active, effects, "CURRENT_RUSTC_VERSION", Some(102090), None), /// Allows `X..Y` patterns. (active, exclusive_range_pattern, "1.11.0", Some(37854), None), /// Allows exhaustive pattern matching on types that contain uninhabited types. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 3c5bff3812a..36600004404 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -723,6 +723,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ and it is only intended to be used in `alloc`." ), + rustc_attr!( + rustc_host, AttributeType::Normal, template!(Word), ErrorFollowing, + "#[rustc_host] annotates const generic parameters as the `host` effect param, \ + and it is only intended for internal use and as a desugaring." + ), + BuiltinAttribute { name: sym::rustc_diagnostic_item, // FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`. diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index ad26c495c02..0738961d6ce 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -288,6 +288,11 @@ hir_analysis_unrecognized_intrinsic_function = unrecognized intrinsic function: `{$name}` .label = unrecognized intrinsic +hir_analysis_unused_associated_type_bounds = + unnecessary associated type bound for not object safe associated type + .note = this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`. + .suggestion = remove this bound + hir_analysis_value_of_associated_struct_already_specified = the value of the associated type `{$item_name}` (from trait `{$def_path}`) is already specified .label = re-bound here diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index 89677141f38..b13de770137 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -363,7 +363,8 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { ); emitted_bad_param_err = true; } - tcx.mk_bound( + Ty::new_bound( + tcx, ty::INNERMOST, ty::BoundTy { var: ty::BoundVar::from_usize(num_bound_vars), @@ -386,11 +387,10 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { .type_of(param.def_id) .no_bound_vars() .expect("ct params cannot have early bound vars"); - tcx.mk_const( - ty::ConstKind::Bound( - ty::INNERMOST, - ty::BoundVar::from_usize(num_bound_vars), - ), + ty::Const::new_bound( + tcx, + ty::INNERMOST, + ty::BoundVar::from_usize(num_bound_vars), ty, ) .into() @@ -528,14 +528,14 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { } let reported = err.emit(); term = match def_kind { - hir::def::DefKind::AssocTy => tcx.ty_error(reported).into(), - hir::def::DefKind::AssocConst => tcx - .const_error( - tcx.type_of(assoc_item_def_id) - .subst(tcx, projection_ty.skip_binder().substs), - reported, - ) - .into(), + hir::def::DefKind::AssocTy => Ty::new_error(tcx, reported).into(), + hir::def::DefKind::AssocConst => ty::Const::new_error( + tcx, + reported, + tcx.type_of(assoc_item_def_id) + .subst(tcx, projection_ty.skip_binder().substs), + ) + .into(), _ => unreachable!(), }; } @@ -559,7 +559,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { // type bound into a trait predicate, since we only want to add predicates // for the `Self` type. if !only_self_bounds.0 { - let param_ty = tcx.mk_alias(ty::Projection, projection_ty.skip_binder()); + let param_ty = Ty::new_alias(tcx, ty::Projection, projection_ty.skip_binder()); self.add_bounds( param_ty, ast_bounds.iter(), diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index dc17ef7048d..ddf99853b2e 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -357,7 +357,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let projection_ty = pred.skip_binder().projection_ty; let substs_with_infer_self = tcx.mk_substs_from_iter( - std::iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into()) + std::iter::once(Ty::new_var(tcx, ty::TyVid::from_u32(0)).into()) .chain(projection_ty.substs.iter().skip(1)), ); diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 2f5bcf8d647..3d698462840 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -6,14 +6,13 @@ mod bounds; mod errors; pub mod generics; mod lint; +mod object_safety; use crate::astconv::errors::prohibit_assoc_ty_binding; use crate::astconv::generics::{check_generic_arg_count, create_substs_for_generic_args}; use crate::bounds::Bounds; use crate::collect::HirPlaceholderCollector; -use crate::errors::{ - AmbiguousLifetimeBound, TraitObjectDeclaredWithNoTraits, TypeofReservedKeywordUsed, -}; +use crate::errors::{AmbiguousLifetimeBound, TypeofReservedKeywordUsed}; use crate::middle::resolve_bound_vars as rbv; use crate::require_c_abi_if_c_variadic; use rustc_ast::TraitObjectSyntax; @@ -31,24 +30,17 @@ use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef}; -use rustc_middle::ty::DynKind; use rustc_middle::ty::GenericParamDefKind; -use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{self, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::{sym, Span, DUMMY_SP}; use rustc_target::spec::abi; -use rustc_trait_selection::traits::error_reporting::report_object_safety_error; use rustc_trait_selection::traits::wf::object_region_bounds; -use rustc_trait_selection::traits::{ - self, astconv_object_safety_violations, NormalizeExt, ObligationCtxt, -}; +use rustc_trait_selection::traits::{self, NormalizeExt, ObligationCtxt}; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; -use smallvec::{smallvec, SmallVec}; -use std::collections::BTreeSet; use std::fmt::Display; use std::slice; @@ -451,7 +443,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } if let (hir::TyKind::Infer, false) = (&ty.kind, self.astconv.allow_ty_infer()) { self.inferred_params.push(ty.span); - tcx.ty_error_misc().into() + Ty::new_misc_error(tcx).into() } else { self.astconv.ast_ty_to_ty(ty).into() } @@ -482,7 +474,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.astconv.ct_infer(ty, Some(param), inf.span).into() } else { self.inferred_params.push(inf.span); - tcx.const_error_misc(ty).into() + ty::Const::new_misc_error(tcx, ty).into() } } _ => unreachable!(), @@ -520,14 +512,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { _ => false, }) { // Avoid ICE #86756 when type error recovery goes awry. - return tcx.ty_error_misc().into(); + return Ty::new_misc_error(tcx).into(); } tcx.at(self.span).type_of(param.def_id).subst(tcx, substs).into() } else if infer_args { self.astconv.ty_infer(Some(param), self.span).into() } else { // We've already errored above about the mismatch. - tcx.ty_error_misc().into() + Ty::new_misc_error(tcx).into() } } GenericParamDefKind::Const { has_default } => { @@ -537,7 +529,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .no_bound_vars() .expect("const parameter types cannot be generic"); if let Err(guar) = ty.error_reported() { - return tcx.const_error(ty, guar).into(); + return ty::Const::new_error(tcx, guar, ty).into(); } if !infer_args && has_default { tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into() @@ -546,7 +538,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.astconv.ct_infer(ty, Some(param), self.span).into() } else { // We've already errored above about the mismatch. - tcx.const_error_misc(ty).into() + ty::Const::new_misc_error(tcx, ty).into() } } } @@ -920,387 +912,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // referencing a single opaque type) get encoded as a type alias that normalization will // then actually instantiate the where bounds of. let alias_ty = self.tcx().mk_alias_ty(did, substs); - self.tcx().mk_alias(ty::Weak, alias_ty) + Ty::new_alias(self.tcx(), ty::Weak, alias_ty) } else { ty.subst(self.tcx(), substs) } } - fn conv_object_ty_poly_trait_ref( - &self, - span: Span, - hir_trait_bounds: &[hir::PolyTraitRef<'_>], - lifetime: &hir::Lifetime, - borrowed: bool, - representation: DynKind, - ) -> Ty<'tcx> { - let tcx = self.tcx(); - - let mut bounds = Bounds::default(); - let mut potential_assoc_types = Vec::new(); - let dummy_self = self.tcx().types.trait_object_dummy_self; - for trait_bound in hir_trait_bounds.iter().rev() { - if let GenericArgCountResult { - correct: - Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }), - .. - } = self.instantiate_poly_trait_ref( - &trait_bound.trait_ref, - trait_bound.span, - ty::BoundConstness::NotConst, - ty::ImplPolarity::Positive, - dummy_self, - &mut bounds, - false, - // FIXME: This should be `true`, but we don't really handle - // associated type bounds or type aliases in objects in a way - // that makes this meaningful, I think. - OnlySelfBounds(false), - ) { - potential_assoc_types.extend(cur_potential_assoc_types); - } - } - - let mut trait_bounds = vec![]; - let mut projection_bounds = vec![]; - for (pred, span) in bounds.clauses() { - let bound_pred = pred.kind(); - match bound_pred.skip_binder() { - ty::ClauseKind::Trait(trait_pred) => { - assert_eq!(trait_pred.polarity, ty::ImplPolarity::Positive); - trait_bounds.push(( - bound_pred.rebind(trait_pred.trait_ref), - span, - trait_pred.constness, - )); - } - ty::ClauseKind::Projection(proj) => { - projection_bounds.push((bound_pred.rebind(proj), span)); - } - ty::ClauseKind::TypeOutlives(_) => { - // Do nothing, we deal with regions separately - } - ty::ClauseKind::RegionOutlives(_) - | ty::ClauseKind::ConstArgHasType(..) - | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) - | ty::ClauseKind::TypeWellFormedFromEnv(_) => { - bug!() - } - } - } - - // Expand trait aliases recursively and check that only one regular (non-auto) trait - // is used and no 'maybe' bounds are used. - let expanded_traits = - traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b, _)| (a, b))); - - let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits - .filter(|i| i.trait_ref().self_ty().skip_binder() == dummy_self) - .partition(|i| tcx.trait_is_auto(i.trait_ref().def_id())); - if regular_traits.len() > 1 { - let first_trait = ®ular_traits[0]; - let additional_trait = ®ular_traits[1]; - let mut err = struct_span_err!( - tcx.sess, - additional_trait.bottom().1, - E0225, - "only auto traits can be used as additional traits in a trait object" - ); - additional_trait.label_with_exp_info( - &mut err, - "additional non-auto trait", - "additional use", - ); - first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use"); - err.help(format!( - "consider creating a new trait with all of these as supertraits and using that \ - trait here instead: `trait NewTrait: {} {{}}`", - regular_traits - .iter() - .map(|t| t.trait_ref().print_only_trait_path().to_string()) - .collect::<Vec<_>>() - .join(" + "), - )); - err.note( - "auto-traits like `Send` and `Sync` are traits that have special properties; \ - for more information on them, visit \ - <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>", - ); - err.emit(); - } - - if regular_traits.is_empty() && auto_traits.is_empty() { - let trait_alias_span = trait_bounds - .iter() - .map(|&(trait_ref, _, _)| trait_ref.def_id()) - .find(|&trait_ref| tcx.is_trait_alias(trait_ref)) - .map(|trait_ref| tcx.def_span(trait_ref)); - let reported = - tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span }); - return tcx.ty_error(reported); - } - - // Check that there are no gross object safety violations; - // most importantly, that the supertraits don't contain `Self`, - // to avoid ICEs. - for item in ®ular_traits { - let object_safety_violations = - astconv_object_safety_violations(tcx, item.trait_ref().def_id()); - if !object_safety_violations.is_empty() { - let reported = report_object_safety_error( - tcx, - span, - item.trait_ref().def_id(), - &object_safety_violations, - ) - .emit(); - return tcx.ty_error(reported); - } - } - - // Use a `BTreeSet` to keep output in a more consistent order. - let mut associated_types: FxHashMap<Span, BTreeSet<DefId>> = FxHashMap::default(); - - let regular_traits_refs_spans = trait_bounds - .into_iter() - .filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id())); - - for (base_trait_ref, span, constness) in regular_traits_refs_spans { - assert_eq!(constness, ty::BoundConstness::NotConst); - let base_pred: ty::Predicate<'tcx> = base_trait_ref.to_predicate(tcx); - for pred in traits::elaborate(tcx, [base_pred]) { - debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", pred); - - let bound_predicate = pred.kind(); - match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { - let pred = bound_predicate.rebind(pred); - associated_types.entry(span).or_default().extend( - tcx.associated_items(pred.def_id()) - .in_definition_order() - .filter(|item| item.kind == ty::AssocKind::Type) - .filter(|item| item.opt_rpitit_info.is_none()) - .map(|item| item.def_id), - ); - } - ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { - let pred = bound_predicate.rebind(pred); - // A `Self` within the original bound will be substituted with a - // `trait_object_dummy_self`, so check for that. - let references_self = match pred.skip_binder().term.unpack() { - ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()), - ty::TermKind::Const(c) => { - c.ty().walk().any(|arg| arg == dummy_self.into()) - } - }; - - // If the projection output contains `Self`, force the user to - // elaborate it explicitly to avoid a lot of complexity. - // - // The "classically useful" case is the following: - // ``` - // trait MyTrait: FnMut() -> <Self as MyTrait>::MyOutput { - // type MyOutput; - // } - // ``` - // - // Here, the user could theoretically write `dyn MyTrait<Output = X>`, - // but actually supporting that would "expand" to an infinitely-long type - // `fix $ Ï„ → dyn MyTrait<MyOutput = X, Output = <Ï„ as MyTrait>::MyOutput`. - // - // Instead, we force the user to write - // `dyn MyTrait<MyOutput = X, Output = X>`, which is uglier but works. See - // the discussion in #56288 for alternatives. - if !references_self { - // Include projections defined on supertraits. - projection_bounds.push((pred, span)); - } - } - _ => (), - } - } - } - - // `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where <Self as Trait>::Assoc = Foo`. - // So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated - // types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a - // corresponding `Projection` clause - for (projection_bound, _) in &projection_bounds { - for def_ids in associated_types.values_mut() { - def_ids.remove(&projection_bound.projection_def_id()); - } - } - - self.complain_about_missing_associated_types( - associated_types, - potential_assoc_types, - hir_trait_bounds, - ); - - // De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as - // `dyn Trait + Send`. - // We remove duplicates by inserting into a `FxHashSet` to avoid re-ordering - // the bounds - let mut duplicates = FxHashSet::default(); - auto_traits.retain(|i| duplicates.insert(i.trait_ref().def_id())); - debug!("regular_traits: {:?}", regular_traits); - debug!("auto_traits: {:?}", auto_traits); - - // Erase the `dummy_self` (`trait_object_dummy_self`) used above. - let existential_trait_refs = regular_traits.iter().map(|i| { - i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| { - assert_eq!(trait_ref.self_ty(), dummy_self); - - // Verify that `dummy_self` did not leak inside default type parameters. This - // could not be done at path creation, since we need to see through trait aliases. - let mut missing_type_params = vec![]; - let mut references_self = false; - let generics = tcx.generics_of(trait_ref.def_id); - let substs: Vec<_> = trait_ref - .substs - .iter() - .enumerate() - .skip(1) // Remove `Self` for `ExistentialPredicate`. - .map(|(index, arg)| { - if arg == dummy_self.into() { - let param = &generics.params[index]; - missing_type_params.push(param.name); - return tcx.ty_error_misc().into(); - } else if arg.walk().any(|arg| arg == dummy_self.into()) { - references_self = true; - return tcx.ty_error_misc().into(); - } - arg - }) - .collect(); - let substs = tcx.mk_substs(&substs); - - let span = i.bottom().1; - let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| { - hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id) - && hir_bound.span.contains(span) - }); - self.complain_about_missing_type_params( - missing_type_params, - trait_ref.def_id, - span, - empty_generic_args, - ); - - if references_self { - let def_id = i.bottom().0.def_id(); - let mut err = struct_span_err!( - tcx.sess, - i.bottom().1, - E0038, - "the {} `{}` cannot be made into an object", - tcx.def_descr(def_id), - tcx.item_name(def_id), - ); - err.note( - rustc_middle::traits::ObjectSafetyViolation::SupertraitSelf(smallvec![]) - .error_msg(), - ); - err.emit(); - } - - ty::ExistentialTraitRef { def_id: trait_ref.def_id, substs } - }) - }); - - let existential_projections = projection_bounds - .iter() - // We filter out traits that don't have `Self` as their self type above, - // we need to do the same for projections. - .filter(|(bound, _)| bound.skip_binder().self_ty() == dummy_self) - .map(|(bound, _)| { - bound.map_bound(|mut b| { - assert_eq!(b.projection_ty.self_ty(), dummy_self); - - // Like for trait refs, verify that `dummy_self` did not leak inside default type - // parameters. - let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| { - if arg.walk().any(|arg| arg == dummy_self.into()) { - return true; - } - false - }); - if references_self { - let guar = tcx.sess.delay_span_bug( - span, - "trait object projection bounds reference `Self`", - ); - let substs: Vec<_> = b - .projection_ty - .substs - .iter() - .map(|arg| { - if arg.walk().any(|arg| arg == dummy_self.into()) { - return tcx.ty_error(guar).into(); - } - arg - }) - .collect(); - b.projection_ty.substs = tcx.mk_substs(&substs); - } - - ty::ExistentialProjection::erase_self_ty(tcx, b) - }) - }); - - let regular_trait_predicates = existential_trait_refs - .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait)); - let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| { - ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id())) - }); - // N.b. principal, projections, auto traits - // FIXME: This is actually wrong with multiple principals in regards to symbol mangling - let mut v = regular_trait_predicates - .chain( - existential_projections.map(|x| x.map_bound(ty::ExistentialPredicate::Projection)), - ) - .chain(auto_trait_predicates) - .collect::<SmallVec<[_; 8]>>(); - v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); - v.dedup(); - let existential_predicates = tcx.mk_poly_existential_predicates(&v); - - // Use explicitly-specified region bound. - let region_bound = if !lifetime.is_elided() { - self.ast_region_to_region(lifetime, None) - } else { - self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| { - if tcx.named_bound_var(lifetime.hir_id).is_some() { - self.ast_region_to_region(lifetime, None) - } else { - self.re_infer(None, span).unwrap_or_else(|| { - let mut err = struct_span_err!( - tcx.sess, - span, - E0228, - "the lifetime bound for this object type cannot be deduced \ - from context; please supply an explicit bound" - ); - let e = if borrowed { - // We will have already emitted an error E0106 complaining about a - // missing named lifetime in `&dyn Trait`, so we elide this one. - err.delay_as_bug() - } else { - err.emit() - }; - ty::Region::new_error(tcx, e) - }) - } - }) - }; - debug!("region_bound: {:?}", region_bound); - - let ty = tcx.mk_dynamic(existential_predicates, region_bound, representation); - debug!("trait_object_type: {:?}", ty); - ty - } - fn report_ambiguous_associated_type( &self, span: Span, @@ -1893,6 +1510,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) -> Result<Option<(Ty<'tcx>, DefId)>, ErrorGuaranteed> { let tcx = self.tcx(); + // Don't attempt to look up inherent associated types when the feature is not enabled. + // Theoretically it'd be fine to do so since we feature-gate their definition site. + // However, due to current limitations of the implementation (caused by us performing + // selection in AstConv), IATs can lead to cycle errors (#108491, #110106) which mask the + // feature-gate error, needlessly confusing users that use IATs by accident (#113265). + if !tcx.features().inherent_associated_types { + return Ok(None); + } + let candidates: Vec<_> = tcx .inherent_impls(adt_did) .iter() @@ -1903,11 +1529,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { return Ok(None); } - if !tcx.features().inherent_associated_types { - tcx.sess - .delay_span_bug(span, "found inherent assoc type without the feature being gated"); - } - // // Select applicable inherent associated type candidates modulo regions. // @@ -1952,10 +1573,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { match *ty.kind() { - ty::Bound(_, bv) => self.tcx.mk_placeholder(ty::PlaceholderType { - universe: self.universe, - bound: bv, - }), + ty::Bound(_, bv) => Ty::new_placeholder( + self.tcx, + ty::PlaceholderType { universe: self.universe, bound: bv }, + ), _ => ty.super_fold_with(self), } } @@ -1967,7 +1588,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assert!(!ct.ty().has_escaping_bound_vars()); match ct.kind() { - ty::ConstKind::Bound(_, bv) => self.tcx.mk_const( + ty::ConstKind::Bound(_, bv) => ty::Const::new_placeholder( + self.tcx, ty::PlaceholderConst { universe: self.universe, bound: bv }, ct.ty(), ), @@ -2043,7 +1665,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .chain(substs.into_iter().skip(parent_substs.len())), ); - let ty = tcx.mk_alias(ty::Inherent, tcx.mk_alias_ty(assoc_item, substs)); + let ty = Ty::new_alias(tcx, ty::Inherent, tcx.mk_alias_ty(assoc_item, substs)); return Ok(Some((ty, assoc_item))); } @@ -2228,7 +1850,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &[path_str], item_segment.ident.name, ); - return tcx.ty_error(reported) + return Ty::new_error(tcx,reported) }; debug!("qpath_to_ty: self_type={:?}", self_ty); @@ -2251,7 +1873,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!("qpath_to_ty: trait_ref={:?}", trait_ref); - tcx.mk_projection(item_def_id, item_substs) + Ty::new_projection(tcx, item_def_id, item_substs) } pub fn prohibit_generics<'a>( @@ -2514,7 +2136,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.note("`impl Trait` types can't have type parameters"); }); let substs = self.ast_path_substs_for_ty(span, did, item_segment.0); - tcx.mk_opaque(did, substs) + Ty::new_opaque(tcx, did, substs) } Res::Def( DefKind::Enum @@ -2566,16 +2188,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { var: ty::BoundVar::from_u32(index), kind: ty::BoundTyKind::Param(def_id, name), }; - tcx.mk_bound(debruijn, br) + Ty::new_bound(tcx, debruijn, br) } Some(rbv::ResolvedArg::EarlyBound(_)) => { let def_id = def_id.expect_local(); let item_def_id = tcx.hir().ty_param_owner(def_id); let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id.to_def_id()]; - tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id)) + Ty::new_param(tcx, index, tcx.hir().ty_param_name(def_id)) } - Some(rbv::ResolvedArg::Error(guar)) => tcx.ty_error(guar), + Some(rbv::ResolvedArg::Error(guar)) => Ty::new_error(tcx, guar), arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"), } } @@ -2687,7 +2309,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { { err.span_note(impl_.self_ty.span, "not a concrete type"); } - tcx.ty_error(err.emit()) + Ty::new_error(tcx, err.emit()) } else { ty } @@ -2728,9 +2350,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { match prim_ty { hir::PrimTy::Bool => tcx.types.bool, hir::PrimTy::Char => tcx.types.char, - hir::PrimTy::Int(it) => tcx.mk_mach_int(ty::int_ty(it)), - hir::PrimTy::Uint(uit) => tcx.mk_mach_uint(ty::uint_ty(uit)), - hir::PrimTy::Float(ft) => tcx.mk_mach_float(ty::float_ty(ft)), + hir::PrimTy::Int(it) => Ty::new_int(tcx, ty::int_ty(it)), + hir::PrimTy::Uint(uit) => Ty::new_uint(tcx, ty::uint_ty(uit)), + hir::PrimTy::Float(ft) => Ty::new_float(tcx, ty::float_ty(ft)), hir::PrimTy::Str => tcx.types.str_, } } @@ -2740,7 +2362,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .sess .delay_span_bug(path.span, "path with `Res::Err` but no error emitted"); self.set_tainted_by_errors(e); - self.tcx().ty_error(e) + Ty::new_error(self.tcx(), e) } _ => span_bug!(span, "unexpected resolution: {:?}", path.res), } @@ -2765,31 +2387,27 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let tcx = self.tcx(); let result_ty = match &ast_ty.kind { - hir::TyKind::Slice(ty) => tcx.mk_slice(self.ast_ty_to_ty(ty)), + hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.ast_ty_to_ty(ty)), hir::TyKind::Ptr(mt) => { - tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl }) + Ty::new_ptr(tcx, ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl }) } hir::TyKind::Ref(region, mt) => { let r = self.ast_region_to_region(region, None); debug!(?r); let t = self.ast_ty_to_ty_inner(mt.ty, true, false); - tcx.mk_ref(r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl }) + Ty::new_ref(tcx, r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl }) } hir::TyKind::Never => tcx.types.never, hir::TyKind::Tup(fields) => { - tcx.mk_tup_from_iter(fields.iter().map(|t| self.ast_ty_to_ty(t))) + Ty::new_tup_from_iter(tcx, fields.iter().map(|t| self.ast_ty_to_ty(t))) } hir::TyKind::BareFn(bf) => { require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span); - tcx.mk_fn_ptr(self.ty_of_fn( - ast_ty.hir_id, - bf.unsafety, - bf.abi, - bf.decl, - None, - Some(ast_ty), - )) + Ty::new_fn_ptr( + tcx, + self.ty_of_fn(ast_ty.hir_id, bf.unsafety, bf.abi, bf.decl, None, Some(ast_ty)), + ) } hir::TyKind::TraitObject(bounds, lifetime, repr) => { self.maybe_lint_bare_trait(ast_ty, in_path); @@ -2798,7 +2416,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { TraitObjectSyntax::DynStar => ty::DynStar, }; - self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed, repr) + self.conv_object_ty_poly_trait_ref( + ast_ty.span, + ast_ty.hir_id, + bounds, + lifetime, + borrowed, + repr, + ) } hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { debug!(?maybe_qself, ?path); @@ -2829,7 +2454,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let ty = self.ast_ty_to_ty_inner(qself, false, true); self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, qself, segment, false) .map(|(ty, _, _)| ty) - .unwrap_or_else(|guar| tcx.ty_error(guar)) + .unwrap_or_else(|guar| Ty::new_error(tcx, guar)) } &hir::TyKind::Path(hir::QPath::LangItem(lang_item, span, _)) => { let def_id = tcx.require_lang_item(lang_item, Some(span)); @@ -2853,7 +2478,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } }; - tcx.mk_array_with_const_len(self.ast_ty_to_ty(ty), length) + Ty::new_array_with_const_len(tcx, self.ast_ty_to_ty(ty), length) } hir::TyKind::Typeof(e) => { let ty_erased = tcx.type_of(e.def_id).subst_identity(); @@ -2877,7 +2502,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // handled specially and will not descend into this routine. self.ty_infer(None, ast_ty.span) } - hir::TyKind::Err(guar) => tcx.ty_error(*guar), + hir::TyKind::Err(guar) => Ty::new_error(tcx, *guar), }; self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span); @@ -2914,7 +2539,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }); debug!("impl_trait_ty_to_ty: substs={:?}", substs); - if in_trait { tcx.mk_projection(def_id, substs) } else { tcx.mk_opaque(def_id, substs) } + if in_trait { + Ty::new_projection(tcx, def_id, substs) + } else { + Ty::new_opaque(tcx, def_id, substs) + } } pub fn ty_of_arg(&self, ty: &hir::Ty<'_>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> { @@ -2983,7 +2612,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.ast_ty_to_ty(output) } } - hir::FnRetTy::DefaultReturn(..) => tcx.mk_unit(), + hir::FnRetTy::DefaultReturn(..) => Ty::new_unit(tcx,), }; debug!(?output_ty); diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs new file mode 100644 index 00000000000..9227ee93451 --- /dev/null +++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs @@ -0,0 +1,408 @@ +use crate::astconv::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds}; +use crate::bounds::Bounds; +use crate::errors::TraitObjectDeclaredWithNoTraits; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_errors::struct_span_err; +use rustc_hir as hir; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::DefId; +use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS; +use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{DynKind, ToPredicate}; +use rustc_span::Span; +use rustc_trait_selection::traits::error_reporting::report_object_safety_error; +use rustc_trait_selection::traits::{self, astconv_object_safety_violations}; + +use smallvec::{smallvec, SmallVec}; +use std::collections::BTreeSet; + +use super::AstConv; + +impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { + pub(super) fn conv_object_ty_poly_trait_ref( + &self, + span: Span, + hir_id: hir::HirId, + hir_trait_bounds: &[hir::PolyTraitRef<'_>], + lifetime: &hir::Lifetime, + borrowed: bool, + representation: DynKind, + ) -> Ty<'tcx> { + let tcx = self.tcx(); + + let mut bounds = Bounds::default(); + let mut potential_assoc_types = Vec::new(); + let dummy_self = self.tcx().types.trait_object_dummy_self; + for trait_bound in hir_trait_bounds.iter().rev() { + if let GenericArgCountResult { + correct: + Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }), + .. + } = self.instantiate_poly_trait_ref( + &trait_bound.trait_ref, + trait_bound.span, + ty::BoundConstness::NotConst, + ty::ImplPolarity::Positive, + dummy_self, + &mut bounds, + false, + // FIXME: This should be `true`, but we don't really handle + // associated type bounds or type aliases in objects in a way + // that makes this meaningful, I think. + OnlySelfBounds(false), + ) { + potential_assoc_types.extend(cur_potential_assoc_types); + } + } + + let mut trait_bounds = vec![]; + let mut projection_bounds = vec![]; + for (pred, span) in bounds.clauses() { + let bound_pred = pred.kind(); + match bound_pred.skip_binder() { + ty::ClauseKind::Trait(trait_pred) => { + assert_eq!(trait_pred.polarity, ty::ImplPolarity::Positive); + trait_bounds.push(( + bound_pred.rebind(trait_pred.trait_ref), + span, + trait_pred.constness, + )); + } + ty::ClauseKind::Projection(proj) => { + projection_bounds.push((bound_pred.rebind(proj), span)); + } + ty::ClauseKind::TypeOutlives(_) => { + // Do nothing, we deal with regions separately + } + ty::ClauseKind::RegionOutlives(_) + | ty::ClauseKind::ConstArgHasType(..) + | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::ConstEvaluatable(_) => { + bug!() + } + } + } + + // Expand trait aliases recursively and check that only one regular (non-auto) trait + // is used and no 'maybe' bounds are used. + let expanded_traits = + traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b, _)| (a, b))); + + let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits + .filter(|i| i.trait_ref().self_ty().skip_binder() == dummy_self) + .partition(|i| tcx.trait_is_auto(i.trait_ref().def_id())); + if regular_traits.len() > 1 { + let first_trait = ®ular_traits[0]; + let additional_trait = ®ular_traits[1]; + let mut err = struct_span_err!( + tcx.sess, + additional_trait.bottom().1, + E0225, + "only auto traits can be used as additional traits in a trait object" + ); + additional_trait.label_with_exp_info( + &mut err, + "additional non-auto trait", + "additional use", + ); + first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use"); + err.help(format!( + "consider creating a new trait with all of these as supertraits and using that \ + trait here instead: `trait NewTrait: {} {{}}`", + regular_traits + .iter() + .map(|t| t.trait_ref().print_only_trait_path().to_string()) + .collect::<Vec<_>>() + .join(" + "), + )); + err.note( + "auto-traits like `Send` and `Sync` are traits that have special properties; \ + for more information on them, visit \ + <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>", + ); + err.emit(); + } + + if regular_traits.is_empty() && auto_traits.is_empty() { + let trait_alias_span = trait_bounds + .iter() + .map(|&(trait_ref, _, _)| trait_ref.def_id()) + .find(|&trait_ref| tcx.is_trait_alias(trait_ref)) + .map(|trait_ref| tcx.def_span(trait_ref)); + let reported = + tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span }); + return Ty::new_error(tcx, reported); + } + + // Check that there are no gross object safety violations; + // most importantly, that the supertraits don't contain `Self`, + // to avoid ICEs. + for item in ®ular_traits { + let object_safety_violations = + astconv_object_safety_violations(tcx, item.trait_ref().def_id()); + if !object_safety_violations.is_empty() { + let reported = report_object_safety_error( + tcx, + span, + item.trait_ref().def_id(), + &object_safety_violations, + ) + .emit(); + return Ty::new_error(tcx, reported); + } + } + + // Use a `BTreeSet` to keep output in a more consistent order. + let mut associated_types: FxHashMap<Span, BTreeSet<DefId>> = FxHashMap::default(); + + let regular_traits_refs_spans = trait_bounds + .into_iter() + .filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id())); + + for (base_trait_ref, span, constness) in regular_traits_refs_spans { + assert_eq!(constness, ty::BoundConstness::NotConst); + let base_pred: ty::Predicate<'tcx> = base_trait_ref.to_predicate(tcx); + for pred in traits::elaborate(tcx, [base_pred]) { + debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", pred); + + let bound_predicate = pred.kind(); + match bound_predicate.skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { + let pred = bound_predicate.rebind(pred); + associated_types.entry(span).or_default().extend( + tcx.associated_items(pred.def_id()) + .in_definition_order() + .filter(|item| item.kind == ty::AssocKind::Type) + .filter(|item| item.opt_rpitit_info.is_none()) + .map(|item| item.def_id), + ); + } + ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { + let pred = bound_predicate.rebind(pred); + // A `Self` within the original bound will be substituted with a + // `trait_object_dummy_self`, so check for that. + let references_self = match pred.skip_binder().term.unpack() { + ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()), + ty::TermKind::Const(c) => { + c.ty().walk().any(|arg| arg == dummy_self.into()) + } + }; + + // If the projection output contains `Self`, force the user to + // elaborate it explicitly to avoid a lot of complexity. + // + // The "classically useful" case is the following: + // ``` + // trait MyTrait: FnMut() -> <Self as MyTrait>::MyOutput { + // type MyOutput; + // } + // ``` + // + // Here, the user could theoretically write `dyn MyTrait<Output = X>`, + // but actually supporting that would "expand" to an infinitely-long type + // `fix $ Ï„ → dyn MyTrait<MyOutput = X, Output = <Ï„ as MyTrait>::MyOutput`. + // + // Instead, we force the user to write + // `dyn MyTrait<MyOutput = X, Output = X>`, which is uglier but works. See + // the discussion in #56288 for alternatives. + if !references_self { + // Include projections defined on supertraits. + projection_bounds.push((pred, span)); + } + } + _ => (), + } + } + } + + // `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where <Self as Trait>::Assoc = Foo`. + // So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated + // types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a + // corresponding `Projection` clause + for def_ids in associated_types.values_mut() { + for (projection_bound, span) in &projection_bounds { + let def_id = projection_bound.projection_def_id(); + def_ids.remove(&def_id); + if tcx.generics_require_sized_self(def_id) { + tcx.emit_spanned_lint( + UNUSED_ASSOCIATED_TYPE_BOUNDS, + hir_id, + *span, + crate::errors::UnusedAssociatedTypeBounds { span: *span }, + ); + } + } + // If the associated type has a `where Self: Sized` bound, we do not need to constrain the associated + // type in the `dyn Trait`. + def_ids.retain(|def_id| !tcx.generics_require_sized_self(def_id)); + } + + self.complain_about_missing_associated_types( + associated_types, + potential_assoc_types, + hir_trait_bounds, + ); + + // De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as + // `dyn Trait + Send`. + // We remove duplicates by inserting into a `FxHashSet` to avoid re-ordering + // the bounds + let mut duplicates = FxHashSet::default(); + auto_traits.retain(|i| duplicates.insert(i.trait_ref().def_id())); + debug!("regular_traits: {:?}", regular_traits); + debug!("auto_traits: {:?}", auto_traits); + + // Erase the `dummy_self` (`trait_object_dummy_self`) used above. + let existential_trait_refs = regular_traits.iter().map(|i| { + i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| { + assert_eq!(trait_ref.self_ty(), dummy_self); + + // Verify that `dummy_self` did not leak inside default type parameters. This + // could not be done at path creation, since we need to see through trait aliases. + let mut missing_type_params = vec![]; + let mut references_self = false; + let generics = tcx.generics_of(trait_ref.def_id); + let substs: Vec<_> = trait_ref + .substs + .iter() + .enumerate() + .skip(1) // Remove `Self` for `ExistentialPredicate`. + .map(|(index, arg)| { + if arg == dummy_self.into() { + let param = &generics.params[index]; + missing_type_params.push(param.name); + return Ty::new_misc_error(tcx).into(); + } else if arg.walk().any(|arg| arg == dummy_self.into()) { + references_self = true; + return Ty::new_misc_error(tcx).into(); + } + arg + }) + .collect(); + let substs = tcx.mk_substs(&substs); + + let span = i.bottom().1; + let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| { + hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id) + && hir_bound.span.contains(span) + }); + self.complain_about_missing_type_params( + missing_type_params, + trait_ref.def_id, + span, + empty_generic_args, + ); + + if references_self { + let def_id = i.bottom().0.def_id(); + let mut err = struct_span_err!( + tcx.sess, + i.bottom().1, + E0038, + "the {} `{}` cannot be made into an object", + tcx.def_descr(def_id), + tcx.item_name(def_id), + ); + err.note( + rustc_middle::traits::ObjectSafetyViolation::SupertraitSelf(smallvec![]) + .error_msg(), + ); + err.emit(); + } + + ty::ExistentialTraitRef { def_id: trait_ref.def_id, substs } + }) + }); + + let existential_projections = projection_bounds + .iter() + // We filter out traits that don't have `Self` as their self type above, + // we need to do the same for projections. + .filter(|(bound, _)| bound.skip_binder().self_ty() == dummy_self) + .map(|(bound, _)| { + bound.map_bound(|mut b| { + assert_eq!(b.projection_ty.self_ty(), dummy_self); + + // Like for trait refs, verify that `dummy_self` did not leak inside default type + // parameters. + let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| { + if arg.walk().any(|arg| arg == dummy_self.into()) { + return true; + } + false + }); + if references_self { + let guar = tcx.sess.delay_span_bug( + span, + "trait object projection bounds reference `Self`", + ); + let substs: Vec<_> = b + .projection_ty + .substs + .iter() + .map(|arg| { + if arg.walk().any(|arg| arg == dummy_self.into()) { + return Ty::new_error(tcx, guar).into(); + } + arg + }) + .collect(); + b.projection_ty.substs = tcx.mk_substs(&substs); + } + + ty::ExistentialProjection::erase_self_ty(tcx, b) + }) + }); + + let regular_trait_predicates = existential_trait_refs + .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait)); + let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| { + ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id())) + }); + // N.b. principal, projections, auto traits + // FIXME: This is actually wrong with multiple principals in regards to symbol mangling + let mut v = regular_trait_predicates + .chain( + existential_projections.map(|x| x.map_bound(ty::ExistentialPredicate::Projection)), + ) + .chain(auto_trait_predicates) + .collect::<SmallVec<[_; 8]>>(); + v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); + v.dedup(); + let existential_predicates = tcx.mk_poly_existential_predicates(&v); + + // Use explicitly-specified region bound. + let region_bound = if !lifetime.is_elided() { + self.ast_region_to_region(lifetime, None) + } else { + self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| { + if tcx.named_bound_var(lifetime.hir_id).is_some() { + self.ast_region_to_region(lifetime, None) + } else { + self.re_infer(None, span).unwrap_or_else(|| { + let mut err = struct_span_err!( + tcx.sess, + span, + E0228, + "the lifetime bound for this object type cannot be deduced \ + from context; please supply an explicit bound" + ); + let e = if borrowed { + // We will have already emitted an error E0106 complaining about a + // missing named lifetime in `&dyn Trait`, so we elide this one. + err.delay_as_bug() + } else { + err.emit() + }; + ty::Region::new_error(tcx, e) + }) + } + }) + }; + debug!("region_bound: {:?}", region_bound); + + let ty = Ty::new_dynamic(tcx, existential_predicates, region_bound, representation); + debug!("trait_object_type: {:?}", ty); + ty + } +} diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index 8aa9a2c2734..c07ac35cba3 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -148,8 +148,11 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { return None; } - let (normalized_ty, obligations) = - self.structurally_normalize(tcx.mk_projection(tcx.lang_items().deref_target()?, [ty]))?; + let (normalized_ty, obligations) = self.structurally_normalize(Ty::new_projection( + tcx, + tcx.lang_items().deref_target()?, + [ty], + ))?; debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations); self.state.obligations.extend(obligations); diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 346e153a69d..270b90fa6b2 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -224,7 +224,8 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) { if check_opaque_for_cycles(tcx, item.owner_id.def_id, substs, span, &origin).is_err() { return; } - check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, &origin); + + let _ = check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, &origin); } /// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result @@ -307,9 +308,9 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( { let substs = InternalSubsts::identity_for_item(tcx, def_id); let opaque_identity_ty = if in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() { - tcx.mk_projection(def_id.to_def_id(), substs) + Ty::new_projection(tcx, def_id.to_def_id(), substs) } else { - tcx.mk_opaque(def_id.to_def_id(), substs) + Ty::new_opaque(tcx, def_id.to_def_id(), substs) }; let mut visitor = ProhibitOpaqueVisitor { opaque_identity_ty, @@ -395,7 +396,7 @@ fn check_opaque_meets_bounds<'tcx>( def_id: LocalDefId, span: Span, origin: &hir::OpaqueTyOrigin, -) { +) -> Result<(), ErrorGuaranteed> { let defining_use_anchor = match *origin { hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did, hir::OpaqueTyOrigin::TyAlias { .. } => tcx.impl_trait_parent(def_id), @@ -409,7 +410,7 @@ fn check_opaque_meets_bounds<'tcx>( let ocx = ObligationCtxt::new(&infcx); let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); - let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs); + let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), substs); // `ReErased` regions appear in the "parent_substs" of closures/generators. // We're ignoring them here and replacing them with fresh region variables. @@ -429,10 +430,10 @@ fn check_opaque_meets_bounds<'tcx>( Ok(()) => {} Err(ty_err) => { let ty_err = ty_err.to_string(tcx); - tcx.sess.delay_span_bug( + return Err(tcx.sess.delay_span_bug( span, format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"), - ); + )); } } @@ -447,7 +448,8 @@ fn check_opaque_meets_bounds<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors); + let guar = infcx.err_ctxt().report_fulfillment_errors(&errors); + return Err(guar); } match origin { // Checked when type checking the function containing them. @@ -461,14 +463,15 @@ fn check_opaque_meets_bounds<'tcx>( if tcx.def_kind(tcx.parent(def_id.to_def_id())) == DefKind::OpaqueTy => {} // Can have different predicates to their defining use hir::OpaqueTyOrigin::TyAlias { .. } => { - let wf_tys = ocx.assumed_wf_types(param_env, span, def_id); + let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, def_id)?; let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, wf_tys); let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); - let _ = ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env); + ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?; } } // Clean up after ourselves let _ = infcx.take_opaque_types(); + Ok(()) } fn is_enum_of_nonnullable_ptr<'tcx>( diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 76edeccaf29..22e576e345e 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -271,7 +271,7 @@ fn compare_method_predicate_entailment<'tcx>( infer::HigherRankedType, tcx.fn_sig(impl_m.def_id).subst_identity(), ); - let unnormalized_impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(unnormalized_impl_sig)); + let unnormalized_impl_fty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(unnormalized_impl_sig)); let norm_cause = ObligationCause::misc(impl_m_span, impl_m_def_id); let impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_impl_sig); @@ -288,7 +288,7 @@ fn compare_method_predicate_entailment<'tcx>( // We also have to add the normalized trait signature // as we don't normalize during implied bounds computation. wf_tys.extend(trait_sig.inputs_and_output.iter()); - let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig)); + let trait_fty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(trait_sig)); debug!("compare_impl_method: trait_fty={:?}", trait_fty); @@ -669,11 +669,13 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( ) .fold_with(&mut collector); - debug_assert_ne!( - collector.types.len(), - 0, - "expect >1 RPITITs in call to `collect_return_position_impl_trait_in_trait_tys`" - ); + if !unnormalized_trait_sig.output().references_error() { + debug_assert_ne!( + collector.types.len(), + 0, + "expect >1 RPITITs in call to `collect_return_position_impl_trait_in_trait_tys`" + ); + } let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig); trait_sig.error_reported()?; @@ -803,7 +805,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( return_span, }) { Ok(ty) => ty, - Err(guar) => tcx.ty_error(guar), + Err(guar) => Ty::new_error(tcx, guar), }; collected_tys.insert(def_id, ty::EarlyBinder::bind(ty)); } @@ -812,7 +814,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( return_span, format!("could not fully resolve: {ty} => {err:?}"), ); - collected_tys.insert(def_id, ty::EarlyBinder::bind(tcx.ty_error(reported))); + collected_tys.insert(def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, reported))); } } } @@ -916,7 +918,7 @@ impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> { _ => arg.try_fold_with(self)?, }); } - Ok(self.tcx.mk_opaque(def_id, self.tcx.mk_substs(&mapped_substs))) + Ok(Ty::new_opaque(self.tcx, def_id, self.tcx.mk_substs(&mapped_substs))) } else { t.try_super_fold_with(self) } @@ -2027,7 +2029,8 @@ pub(super) fn check_type_bounds<'tcx>( let kind = ty::BoundTyKind::Param(param.def_id, param.name); let bound_var = ty::BoundVariableKind::Ty(kind); bound_vars.push(bound_var); - tcx.mk_bound( + Ty::new_bound( + tcx, ty::INNERMOST, ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, ) @@ -2047,11 +2050,10 @@ pub(super) fn check_type_bounds<'tcx>( GenericParamDefKind::Const { .. } => { let bound_var = ty::BoundVariableKind::Const; bound_vars.push(bound_var); - tcx.mk_const( - ty::ConstKind::Bound( - ty::INNERMOST, - ty::BoundVar::from_usize(bound_vars.len() - 1), - ), + ty::Const::new_bound( + tcx, + ty::INNERMOST, + ty::BoundVar::from_usize(bound_vars.len() - 1), tcx.type_of(param.def_id) .no_bound_vars() .expect("const parameter types cannot be generic"), @@ -2121,7 +2123,7 @@ pub(super) fn check_type_bounds<'tcx>( _ => bug!(), } }; - let assumed_wf_types = ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty_def_id); + let assumed_wf_types = ocx.assumed_wf_types_and_report_errors(param_env, impl_ty_def_id)?; let normalize_cause = ObligationCause::new( impl_ty_span, diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 36c468e7789..1248f991cc4 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -11,7 +11,7 @@ use hir::def_id::DefId; use rustc_errors::{struct_span_err, DiagnosticMessage}; use rustc_hir as hir; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_target::spec::abi::Abi; @@ -53,14 +53,14 @@ fn equate_intrinsic_type<'tcx>( && gen_count_ok(own_counts.types, n_tps, "type") && gen_count_ok(own_counts.consts, 0, "const") { - let fty = tcx.mk_fn_ptr(sig); + let fty = Ty::new_fn_ptr(tcx, sig); let it_def_id = it.owner_id.def_id; let cause = ObligationCause::new(it.span, it_def_id, ObligationCauseCode::IntrinsicType); require_same_types( tcx, &cause, ty::ParamEnv::empty(), // FIXME: do all intrinsics have an empty param env? - tcx.mk_fn_ptr(tcx.fn_sig(it.owner_id).subst_identity()), + Ty::new_fn_ptr(tcx, tcx.fn_sig(it.owner_id).subst_identity()), fty, ); } @@ -134,7 +134,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir /// Remember to add all intrinsics here, in `compiler/rustc_codegen_llvm/src/intrinsic.rs`, /// and in `library/core/src/intrinsics.rs`. pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { - let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n))); + let param = |n| Ty::new_param(tcx, n, Symbol::intern(&format!("P{}", n))); let intrinsic_id = it.owner_id.to_def_id(); let intrinsic_name = tcx.item_name(intrinsic_id); let name_str = intrinsic_name.as_str(); @@ -156,7 +156,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrEnv }, ); let va_list_ty = tcx.type_of(did).subst(tcx, &[region.into()]); - (tcx.mk_ref(env_region, ty::TypeAndMut { ty: va_list_ty, mutbl }), va_list_ty) + (Ty::new_ref(tcx, env_region, ty::TypeAndMut { ty: va_list_ty, mutbl }), va_list_ty) }) }; @@ -168,15 +168,15 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let (n_tps, inputs, output) = match split[1] { "cxchg" | "cxchgweak" => ( 1, - vec![tcx.mk_mut_ptr(param(0)), param(0), param(0)], - tcx.mk_tup(&[param(0), tcx.types.bool]), + vec![Ty::new_mut_ptr(tcx, param(0)), param(0), param(0)], + Ty::new_tup(tcx, &[param(0), tcx.types.bool]), ), - "load" => (1, vec![tcx.mk_imm_ptr(param(0))], param(0)), - "store" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()), + "load" => (1, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)), + "store" => (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx)), "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" | "min" | "umax" - | "umin" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], param(0)), - "fence" | "singlethreadfence" => (0, Vec::new(), tcx.mk_unit()), + | "umin" => (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], param(0)), + "fence" | "singlethreadfence" => (0, Vec::new(), Ty::new_unit(tcx)), op => { tcx.sess.emit_err(UnrecognizedAtomicOperation { span: it.span, op }); return; @@ -188,19 +188,19 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let (n_tps, inputs, output) = match intrinsic_name { sym::abort => (0, Vec::new(), tcx.types.never), sym::unreachable => (0, Vec::new(), tcx.types.never), - sym::breakpoint => (0, Vec::new(), tcx.mk_unit()), + sym::breakpoint => (0, Vec::new(), Ty::new_unit(tcx)), sym::size_of | sym::pref_align_of | sym::min_align_of | sym::variant_count => { (1, Vec::new(), tcx.types.usize) } sym::size_of_val | sym::min_align_of_val => { - (1, vec![tcx.mk_imm_ptr(param(0))], tcx.types.usize) + (1, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize) } sym::rustc_peek => (1, vec![param(0)], param(0)), sym::caller_location => (0, vec![], tcx.caller_location_ty()), sym::assert_inhabited | sym::assert_zero_valid - | sym::assert_mem_uninitialized_valid => (1, Vec::new(), tcx.mk_unit()), - sym::forget => (1, vec![param(0)], tcx.mk_unit()), + | sym::assert_mem_uninitialized_valid => (1, Vec::new(), Ty::new_unit(tcx)), + sym::forget => (1, vec![param(0)], Ty::new_unit(tcx)), sym::transmute | sym::transmute_unchecked => (2, vec![param(0)], param(1)), sym::prefetch_read_data | sym::prefetch_write_data @@ -208,75 +208,79 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { | sym::prefetch_write_instruction => ( 1, vec![ - tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), + Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), tcx.types.i32, ], - tcx.mk_unit(), + Ty::new_unit(tcx), ), - sym::drop_in_place => (1, vec![tcx.mk_mut_ptr(param(0))], tcx.mk_unit()), + sym::drop_in_place => (1, vec![Ty::new_mut_ptr(tcx, param(0))], Ty::new_unit(tcx)), sym::needs_drop => (1, Vec::new(), tcx.types.bool), - sym::type_name => (1, Vec::new(), tcx.mk_static_str()), + sym::type_name => (1, Vec::new(), Ty::new_static_str(tcx)), sym::type_id => (1, Vec::new(), tcx.types.u128), sym::offset => (2, vec![param(0), param(1)], param(0)), sym::arith_offset => ( 1, vec![ - tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), + Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), tcx.types.isize, ], - tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), + Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), ), sym::option_payload_ptr => { let option_def_id = tcx.require_lang_item(hir::LangItem::Option, None); let p0 = param(0); ( 1, - vec![tcx.mk_ptr(ty::TypeAndMut { - ty: tcx.mk_adt( - tcx.adt_def(option_def_id), - tcx.mk_substs_from_iter([ty::GenericArg::from(p0)].into_iter()), - ), - mutbl: hir::Mutability::Not, - })], - tcx.mk_ptr(ty::TypeAndMut { ty: p0, mutbl: hir::Mutability::Not }), + vec![Ty::new_ptr( + tcx, + ty::TypeAndMut { + ty: Ty::new_adt( + tcx, + tcx.adt_def(option_def_id), + tcx.mk_substs_from_iter([ty::GenericArg::from(p0)].into_iter()), + ), + mutbl: hir::Mutability::Not, + }, + )], + Ty::new_ptr(tcx, ty::TypeAndMut { ty: p0, mutbl: hir::Mutability::Not }), ) } sym::ptr_mask => ( 1, vec![ - tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), + Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), tcx.types.usize, ], - tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), + Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), ), sym::copy | sym::copy_nonoverlapping => ( 1, vec![ - tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), - tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }), + Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), + Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }), tcx.types.usize, ], - tcx.mk_unit(), + Ty::new_unit(tcx), ), sym::volatile_copy_memory | sym::volatile_copy_nonoverlapping_memory => ( 1, vec![ - tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }), - tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), + Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }), + Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), tcx.types.usize, ], - tcx.mk_unit(), + Ty::new_unit(tcx), ), sym::write_bytes | sym::volatile_set_memory => ( 1, vec![ - tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }), + Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }), tcx.types.u8, tcx.types.usize, ], - tcx.mk_unit(), + Ty::new_unit(tcx), ), sym::sqrtf32 => (0, vec![tcx.types.f32], tcx.types.f32), sym::sqrtf64 => (0, vec![tcx.types.f64], tcx.types.f64), @@ -324,10 +328,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::roundevenf64 => (0, vec![tcx.types.f64], tcx.types.f64), sym::volatile_load | sym::unaligned_volatile_load => { - (1, vec![tcx.mk_imm_ptr(param(0))], param(0)) + (1, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)) } sym::volatile_store | sym::unaligned_volatile_store => { - (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()) + (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx)) } sym::ctpop @@ -339,28 +343,34 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { | sym::bitreverse => (1, vec![param(0)], param(0)), sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => { - (1, vec![param(0), param(0)], tcx.mk_tup(&[param(0), tcx.types.bool])) + (1, vec![param(0), param(0)], Ty::new_tup(tcx, &[param(0), tcx.types.bool])) } - sym::ptr_guaranteed_cmp => { - (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.u8) - } + sym::ptr_guaranteed_cmp => ( + 1, + vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))], + tcx.types.u8, + ), sym::const_allocate => { - (0, vec![tcx.types.usize, tcx.types.usize], tcx.mk_mut_ptr(tcx.types.u8)) + (0, vec![tcx.types.usize, tcx.types.usize], Ty::new_mut_ptr(tcx, tcx.types.u8)) } sym::const_deallocate => ( 0, - vec![tcx.mk_mut_ptr(tcx.types.u8), tcx.types.usize, tcx.types.usize], - tcx.mk_unit(), + vec![Ty::new_mut_ptr(tcx, tcx.types.u8), tcx.types.usize, tcx.types.usize], + Ty::new_unit(tcx), ), - sym::ptr_offset_from => { - (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize) - } - sym::ptr_offset_from_unsigned => { - (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.usize) - } + sym::ptr_offset_from => ( + 1, + vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))], + tcx.types.isize, + ), + sym::ptr_offset_from_unsigned => ( + 1, + vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))], + tcx.types.usize, + ), sym::unchecked_div | sym::unchecked_rem | sym::exact_div => { (1, vec![param(0), param(0)], param(0)) } @@ -379,12 +389,14 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { } sym::float_to_int_unchecked => (2, vec![param(0)], param(1)), - sym::assume => (0, vec![tcx.types.bool], tcx.mk_unit()), + sym::assume => (0, vec![tcx.types.bool], Ty::new_unit(tcx)), sym::likely => (0, vec![tcx.types.bool], tcx.types.bool), sym::unlikely => (0, vec![tcx.types.bool], tcx.types.bool), - sym::read_via_copy => (1, vec![tcx.mk_imm_ptr(param(0))], param(0)), - sym::write_via_move => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()), + sym::read_via_copy => (1, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)), + sym::write_via_move => { + (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx)) + } sym::discriminant_value => { let assoc_items = tcx.associated_item_def_ids( @@ -395,48 +407,47 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }; ( 1, - vec![ - tcx.mk_imm_ref( - ty::Region::new_late_bound(tcx, ty::INNERMOST, br), - param(0), - ), - ], - tcx.mk_projection(discriminant_def_id, tcx.mk_substs(&[param(0).into()])), + vec![Ty::new_imm_ref( + tcx, + ty::Region::new_late_bound(tcx, ty::INNERMOST, br), + param(0), + )], + Ty::new_projection(tcx, discriminant_def_id, tcx.mk_substs(&[param(0).into()])), ) } kw::Try => { - let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8); + let mut_u8 = Ty::new_mut_ptr(tcx, tcx.types.u8); let try_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig( [mut_u8], - tcx.mk_unit(), + Ty::new_unit(tcx), false, hir::Unsafety::Normal, Abi::Rust, )); let catch_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig( [mut_u8, mut_u8], - tcx.mk_unit(), + Ty::new_unit(tcx), false, hir::Unsafety::Normal, Abi::Rust, )); ( 0, - vec![tcx.mk_fn_ptr(try_fn_ty), mut_u8, tcx.mk_fn_ptr(catch_fn_ty)], + vec![Ty::new_fn_ptr(tcx, try_fn_ty), mut_u8, Ty::new_fn_ptr(tcx, catch_fn_ty)], tcx.types.i32, ) } sym::va_start | sym::va_end => match mk_va_list_ty(hir::Mutability::Mut) { - Some((va_list_ref_ty, _)) => (0, vec![va_list_ref_ty], tcx.mk_unit()), + Some((va_list_ref_ty, _)) => (0, vec![va_list_ref_ty], Ty::new_unit(tcx)), None => bug!("`va_list` language item needed for C-variadic intrinsics"), }, sym::va_copy => match mk_va_list_ty(hir::Mutability::Not) { Some((va_list_ref_ty, va_list_ty)) => { - let va_list_ptr_ty = tcx.mk_mut_ptr(va_list_ty); - (0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.mk_unit()) + let va_list_ptr_ty = Ty::new_mut_ptr(tcx, va_list_ty); + (0, vec![va_list_ptr_ty, va_list_ref_ty], Ty::new_unit(tcx)) } None => bug!("`va_list` language item needed for C-variadic intrinsics"), }, @@ -446,12 +457,17 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { None => bug!("`va_list` language item needed for C-variadic intrinsics"), }, - sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()), + sym::nontemporal_store => { + (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx)) + } sym::raw_eq => { let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }; - let param_ty = - tcx.mk_imm_ref(ty::Region::new_late_bound(tcx, ty::INNERMOST, br), param(0)); + let param_ty = Ty::new_imm_ref( + tcx, + ty::Region::new_late_bound(tcx, ty::INNERMOST, br), + param(0), + ); (1, vec![param_ty; 2], tcx.types.bool) } @@ -460,7 +476,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::const_eval_select => (4, vec![param(0), param(1), param(2)], param(3)), sym::vtable_size | sym::vtable_align => { - (0, vec![tcx.mk_imm_ptr(tcx.mk_unit())], tcx.types.usize) + (0, vec![Ty::new_imm_ptr(tcx, Ty::new_unit(tcx))], tcx.types.usize) } other => { @@ -479,7 +495,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let param = |n| { let name = Symbol::intern(&format!("P{}", n)); - tcx.mk_ty_param(n, name) + Ty::new_param(tcx, n, name) }; let name = it.ident.name; @@ -521,7 +537,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) sym::simd_fpowi => (1, vec![param(0), tcx.types.i32], param(0)), sym::simd_fma => (1, vec![param(0), param(0), param(0)], param(0)), sym::simd_gather => (3, vec![param(0), param(1), param(2)], param(0)), - sym::simd_scatter => (3, vec![param(0), param(1), param(2)], tcx.mk_unit()), + sym::simd_scatter => (3, vec![param(0), param(1), param(2)], Ty::new_unit(tcx)), sym::simd_insert => (2, vec![param(0), tcx.types.u32, param(1)], param(0)), sym::simd_extract => (2, vec![param(0), tcx.types.u32], param(1)), sym::simd_cast @@ -550,7 +566,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) name if name.as_str().starts_with("simd_shuffle") => { match name.as_str()["simd_shuffle".len()..].parse() { Ok(n) => { - let params = vec![param(0), param(0), tcx.mk_array(tcx.types.u32, n)]; + let params = vec![param(0), param(0), Ty::new_array(tcx, tcx.types.u32, n)]; (2, params, param(1)) } Err(_) => { diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index d34d6f644a7..7a625dd5932 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -105,7 +105,12 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>( } f(&mut wfcx); - let assumed_wf_types = wfcx.ocx.assumed_wf_types(param_env, span, body_def_id); + let assumed_wf_types = match wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id) + { + Ok(wf_types) => wf_types, + Err(_guar) => return, + }; + let implied_bounds = infcx.implied_bounds_tys(param_env, body_def_id, assumed_wf_types); let errors = wfcx.select_all_or_error(); @@ -556,7 +561,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( // our example, the type was `Self`, which will also be // `Self` in the GAT. let ty_param = gat_generics.param_at(*ty_idx, tcx); - let ty_param = tcx.mk_ty_param(ty_param.index, ty_param.name); + let ty_param = Ty::new_param(tcx, ty_param.index, ty_param.name); // Same for the region. In our example, 'a corresponds // to the 'me parameter. let region_param = gat_generics.param_at(*region_a_idx, tcx); diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 2441c8667d4..79cc43edff1 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -336,15 +336,17 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a); let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b }; - check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty)) + check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty)) } (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(mt_b)) => { let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; - check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)) + check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty)) } - (&ty::RawPtr(mt_a), &ty::RawPtr(mt_b)) => check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)), + (&ty::RawPtr(mt_a), &ty::RawPtr(mt_b)) => { + check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty)) + } (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b)) if def_a.is_struct() && def_b.is_struct() => diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index eb299a1ea79..025bab14021 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -343,7 +343,7 @@ fn emit_orphan_check_error<'tcx>( // That way if we had `Vec<MyType>`, we will properly attribute the // problem to `Vec<T>` and avoid confusing the user if they were to see // `MyType` in the error. - ty::Adt(def, _) => tcx.mk_adt(*def, ty::List::empty()), + ty::Adt(def, _) => Ty::new_adt(tcx, *def, ty::List::empty()), _ => ty, }; let msg = |ty: &str, postfix: &str| { @@ -605,7 +605,9 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: } let self_ty_root = match self_ty.kind() { - ty::Adt(def, _) => tcx.mk_adt(*def, InternalSubsts::identity_for_item(tcx, def.did())), + ty::Adt(def, _) => { + Ty::new_adt(tcx, *def, InternalSubsts::identity_for_item(tcx, def.did())) + } _ => unimplemented!("unexpected self ty {:?}", self_ty), }; diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index d7ac9e7ce73..f47df4f215b 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -380,7 +380,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { } fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { - self.tcx().ty_error_with_message(span, "bad placeholder type") + Ty::new_error_with_message(self.tcx(), span, "bad placeholder type") } fn ct_infer(&self, ty: Ty<'tcx>, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> { @@ -390,7 +390,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { // left alone. r => bug!("unexpected region: {r:?}"), }); - self.tcx().const_error_with_message(ty, span, "bad placeholder constant") + ty::Const::new_error_with_message(self.tcx(), ty, span, "bad placeholder constant") } fn projected_ty_from_poly_trait_ref( @@ -407,7 +407,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { item_segment, trait_ref.substs, ); - self.tcx().mk_projection(item_def_id, item_substs) + Ty::new_projection(self.tcx(), item_def_id, item_substs) } else { // There are no late-bound regions; we can just ignore the binder. let (mut mpart_sugg, mut inferred_sugg) = (None, None); @@ -471,14 +471,15 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { } _ => {} } - self.tcx().ty_error(self.tcx().sess.emit_err( - errors::AssociatedTypeTraitUninferredGenericParams { + Ty::new_error( + self.tcx(), + self.tcx().sess.emit_err(errors::AssociatedTypeTraitUninferredGenericParams { span, inferred_sugg, bound, mpart_sugg, - }, - )) + }), + ) } } @@ -1239,7 +1240,7 @@ fn infer_return_ty_for_fn_sig<'tcx>( } else { ty::Binder::dummy(tcx.mk_fn_sig( fn_sig.inputs().iter().copied(), - tcx.ty_error(guar), + Ty::new_error(tcx, guar), fn_sig.c_variadic, fn_sig.unsafety, fn_sig.abi, @@ -1332,7 +1333,7 @@ fn suggest_impl_trait<'tcx>( let item_ty = ocx.normalize( &ObligationCause::misc(span, def_id), param_env, - tcx.mk_projection(assoc_item_def_id, substs), + Ty::new_projection(tcx, assoc_item_def_id, substs), ); // FIXME(compiler-errors): We may benefit from resolving regions here. if ocx.select_where_possible().is_empty() diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 2206f640529..ccc9f808411 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -9,7 +9,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{kw, Symbol}; -use rustc_span::Span; +use rustc_span::{sym, Span}; pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { use rustc_hir::*; @@ -101,6 +101,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { param_def_id_to_index, has_self: generics.has_self, has_late_bound_regions: generics.has_late_bound_regions, + host_effect_index: None, }; } else { // HACK(eddyb) this provides the correct generics when @@ -226,10 +227,12 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { let has_self = opt_self.is_some(); let mut parent_has_self = false; let mut own_start = has_self as u32; + let mut host_effect_index = None; let parent_count = parent_def_id.map_or(0, |def_id| { let generics = tcx.generics_of(def_id); assert!(!has_self); parent_has_self = generics.has_self; + host_effect_index = generics.host_effect_index; own_start = generics.count() as u32; generics.parent_count + generics.params.len() }); @@ -251,11 +254,11 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // Now create the real type and const parameters. let type_start = own_start - has_self as u32 + params.len() as u32; - let mut i = 0; + let mut i: u32 = 0; let mut next_index = || { let prev = i; i += 1; - prev as u32 + type_start + prev + type_start }; const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \ @@ -295,7 +298,13 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { }) } GenericParamKind::Const { default, .. } => { - if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() { + let is_host_param = tcx.has_attr(param.def_id, sym::rustc_host); + + if !matches!(allow_defaults, Defaults::Allowed) + && default.is_some() + // `rustc_host` effect params are allowed to have defaults. + && !is_host_param + { tcx.sess.span_err( param.span, "defaults for const parameters are only allowed in \ @@ -303,8 +312,18 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { ); } + let index = next_index(); + + if is_host_param { + if let Some(idx) = host_effect_index { + bug!("parent also has host effect param? index: {idx}, def: {def_id:?}"); + } + + host_effect_index = Some(parent_count + index as usize); + } + Some(ty::GenericParamDef { - index: next_index(), + index, name: param.name.ident().name, def_id: param.def_id.to_def_id(), pure_wrt_drop: param.pure_wrt_drop, @@ -356,6 +375,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { param_def_id_to_index, has_self: has_self || parent_has_self, has_late_bound_regions: has_late_bound_regions(tcx, node), + host_effect_index, } } diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 8b3f98493c1..57f74172ed0 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -20,7 +20,8 @@ fn associated_type_bounds<'tcx>( ast_bounds: &'tcx [hir::GenericBound<'tcx>], span: Span, ) -> &'tcx [(ty::Clause<'tcx>, Span)] { - let item_ty = tcx.mk_projection( + let item_ty = Ty::new_projection( + tcx, assoc_item_def_id.to_def_id(), InternalSubsts::identity_for_item(tcx, assoc_item_def_id), ); @@ -91,7 +92,8 @@ pub(super) fn explicit_item_bounds( tcx, opaque_def_id.expect_local(), opaque_ty.bounds, - tcx.mk_projection( + Ty::new_projection( + tcx, def_id.to_def_id(), ty::InternalSubsts::identity_for_item(tcx, def_id), ), @@ -117,9 +119,9 @@ pub(super) fn explicit_item_bounds( }) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); let item_ty = if *in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() { - tcx.mk_projection(def_id.to_def_id(), substs) + Ty::new_projection(tcx, def_id.to_def_id(), substs) } else { - tcx.mk_opaque(def_id.to_def_id(), substs) + Ty::new_opaque(tcx, def_id.to_def_id(), substs) }; opaque_type_bounds(tcx, def_id, bounds, item_ty, *span) } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index b9e71aaa004..12936664130 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -63,7 +63,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen use rustc_hir::*; match tcx.opt_rpitit_info(def_id.to_def_id()) { - Some(ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { + Some(ImplTraitInTraitData::Trait { opaque_def_id, fn_def_id }) => { let opaque_ty_id = tcx.hir().local_def_id_to_hir_id(opaque_def_id.expect_local()); let opaque_ty_node = tcx.hir().get(opaque_ty_id); let Node::Item(&Item { kind: ItemKind::OpaqueTy(OpaqueTy { lifetime_mapping, .. }), .. }) = opaque_ty_node else { @@ -71,6 +71,18 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen }; let mut predicates = Vec::new(); + + // RPITITs should inherit the predicates of their parent. This is + // both to ensure that the RPITITs are only instantiated when the + // parent predicates would hold, and also so that the param-env + // inherits these predicates as assumptions. + let identity_substs = InternalSubsts::identity_for_item(tcx, def_id); + predicates.extend( + tcx.explicit_predicates_of(fn_def_id).instantiate_own(tcx, identity_substs), + ); + + // We also install bidirectional outlives predicates for the RPITIT + // to keep the duplicates lifetimes from opaque lowering in sync. compute_bidirectional_outlives_predicates( tcx, def_id, @@ -89,12 +101,13 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen Some(ImplTraitInTraitData::Impl { fn_def_id }) => { let assoc_item = tcx.associated_item(def_id); - let trait_assoc_predicates = tcx.predicates_of(assoc_item.trait_item_def_id.unwrap()); + let trait_assoc_predicates = + tcx.explicit_predicates_of(assoc_item.trait_item_def_id.unwrap()); let impl_assoc_identity_substs = InternalSubsts::identity_for_item(tcx, def_id); let impl_def_id = tcx.parent(fn_def_id); let impl_trait_ref_substs = - tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder().substs; + tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity().substs; let impl_assoc_substs = impl_assoc_identity_substs.rebase_onto(tcx, impl_def_id, impl_trait_ref_substs); @@ -230,9 +243,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen let name = param.name.ident().name; let param_const = ty::ParamConst::new(index, name); - let ct_ty = tcx.type_of(param.def_id.to_def_id()).subst_identity(); + let ct_ty = tcx + .type_of(param.def_id.to_def_id()) + .no_bound_vars() + .expect("const parameters cannot be generic"); - let ct = tcx.mk_const(param_const, ct_ty); + let ct = ty::Const::new_param(tcx, param_const, ct_ty); predicates.insert(( ty::ClauseKind::ConstArgHasType(ct, ct_ty).to_predicate(tcx), @@ -703,6 +719,7 @@ pub(super) fn type_param_predicates( (item_def_id, def_id, assoc_name): (LocalDefId, LocalDefId, Ident), ) -> ty::GenericPredicates<'_> { use rustc_hir::*; + use rustc_middle::ty::Ty; // In the AST, bounds can derive from two places. Either // written inline like `<T: Foo>` or in a where-clause like @@ -712,7 +729,7 @@ pub(super) fn type_param_predicates( let param_owner = tcx.hir().ty_param_owner(def_id); let generics = tcx.generics_of(param_owner); let index = generics.param_def_id_to_index[&def_id.to_def_id()]; - let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id)); + let ty = Ty::new_param(tcx, index, tcx.hir().ty_param_name(def_id)); // Don't look for bounds where the type parameter isn't in scope. let parent = if item_def_id == param_owner { diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index bd92ee4b550..3755342aef5 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -16,6 +16,7 @@ mod opaque; fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { use hir::*; + use rustc_middle::ty::Ty; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let Node::AnonConst(_) = tcx.hir().get(hir_id) else { panic!() }; @@ -25,13 +26,13 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { let (generics, arg_idx) = match parent_node { // Easy case: arrays repeat expressions. - Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. }) + Node::Ty(&hir::Ty { kind: TyKind::Array(_, ref constant), .. }) | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) if constant.hir_id() == hir_id => { return tcx.types.usize } - Node::Ty(&Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => { + Node::Ty(&hir::Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => { return tcx.typeck(def_id).node_type(e.hir_id) } Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) @@ -67,7 +68,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { ) => { let Some(trait_def_id) = trait_ref.trait_def_id() else { - return tcx.ty_error_with_message(tcx.def_span(def_id), "Could not find trait"); + return Ty::new_error_with_message(tcx,tcx.def_span(def_id), "Could not find trait"); }; let assoc_items = tcx.associated_items(trait_def_id); let assoc_item = assoc_items.find_by_name_and_kind( @@ -79,7 +80,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { .expect("const parameter types cannot be generic") } else { // FIXME(associated_const_equality): add a useful error message here. - tcx.ty_error_with_message(tcx.def_span(def_id), "Could not find associated const on trait") + Ty::new_error_with_message(tcx,tcx.def_span(def_id), "Could not find associated const on trait") } } @@ -99,7 +100,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { // arm would handle this. // // I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU - Node::Ty(hir_ty @ Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => { + Node::Ty(hir_ty @ hir::Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => { // Find the Item containing the associated type so we can create an ItemCtxt. // Using the ItemCtxt convert the HIR for the unresolved assoc type into a // ty which is a fully resolved projection. @@ -137,7 +138,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { (generics, arg_index) } else { // I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU - return tcx.ty_error_with_message( + return Ty::new_error_with_message(tcx, tcx.def_span(def_id), "unexpected non-GAT usage of an anon const", ); @@ -154,7 +155,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { // As there is no relevant param for `def_id`, we simply return // `None` here. let Some(type_dependent_def) = tables.type_dependent_def_id(parent_node_id) else { - return tcx.ty_error_with_message( + return Ty::new_error_with_message(tcx, tcx.def_span(def_id), format!("unable to find type-dependent def for {:?}", parent_node_id), ); @@ -174,12 +175,12 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { (tcx.generics_of(type_dependent_def), idx) } - Node::Ty(&Ty { kind: TyKind::Path(_), .. }) + Node::Ty(&hir::Ty { kind: TyKind::Path(_), .. }) | Node::Expr(&Expr { kind: ExprKind::Path(_) | ExprKind::Struct(..), .. }) | Node::TraitRef(..) | Node::Pat(_) => { let path = match parent_node { - Node::Ty(&Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. }) + Node::Ty(&hir::Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. }) | Node::TraitRef(&TraitRef { path, .. }) => &*path, Node::Expr(&Expr { kind: @@ -195,14 +196,14 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) { path } else { - return tcx.ty_error_with_message( + return Ty::new_error_with_message(tcx, tcx.def_span(def_id), format!("unable to find const parent for {} in pat {:?}", hir_id, pat), ); } } _ => { - return tcx.ty_error_with_message( + return Ty::new_error_with_message(tcx, tcx.def_span(def_id), format!("unexpected const parent path {:?}", parent_node), ); @@ -224,7 +225,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { .position(|ct| ct.hir_id == hir_id) .map(|idx| (idx, seg))) }) else { - return tcx.ty_error_with_message( + return Ty::new_error_with_message(tcx, tcx.def_span(def_id), "no arg matching AnonConst in path", ); @@ -233,7 +234,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { let generics = match tcx.res_generics_def_id(segment.res) { Some(def_id) => tcx.generics_of(def_id), None => { - return tcx.ty_error_with_message( + return Ty::new_error_with_message(tcx, tcx.def_span(def_id), format!("unexpected anon const res {:?} in path: {:?}", segment.res, path), ); @@ -243,7 +244,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { (generics, arg_index) } - _ => return tcx.ty_error_with_message( + _ => return Ty::new_error_with_message(tcx, tcx.def_span(def_id), format!("unexpected const parent in type_of(): {parent_node:?}"), ), @@ -269,7 +270,8 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { { tcx.type_of(param_def_id).no_bound_vars().expect("const parameter types cannot be generic") } else { - return tcx.ty_error_with_message( + return Ty::new_error_with_message( + tcx, tcx.def_span(def_id), format!("const generic parameter not found in {generics:?} at position {arg_idx:?}"), ); @@ -305,6 +307,9 @@ fn get_path_containing_arg_in_pat<'hir>( } pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty<'_>> { + use rustc_hir::*; + use rustc_middle::ty::Ty; + // If we are computing `type_of` the synthesized associated type for an RPITIT in the impl // side, use `collect_return_position_impl_trait_in_trait_tys` to infer the value of the // associated type in the impl. @@ -317,7 +322,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty return map[&assoc_item.trait_item_def_id.unwrap()]; } Err(_) => { - return ty::EarlyBinder::bind(tcx.ty_error_with_message( + return ty::EarlyBinder::bind(Ty::new_error_with_message( + tcx, DUMMY_SP, "Could not collect return position impl trait in trait tys", )); @@ -325,8 +331,6 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty } } - use rustc_hir::*; - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let icx = ItemCtxt::new(tcx, def_id); @@ -335,7 +339,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty Node::TraitItem(item) => match item.kind { TraitItemKind::Fn(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id.to_def_id(), substs) + Ty::new_fn_def(tcx, def_id.to_def_id(), substs) } TraitItemKind::Const(ty, body_id) => body_id .and_then(|body_id| { @@ -360,7 +364,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty Node::ImplItem(item) => match item.kind { ImplItemKind::Fn(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id.to_def_id(), substs) + Ty::new_fn_def(tcx, def_id.to_def_id(), substs) } ImplItemKind::Const(ty, body_id) => { if is_suggestable_infer_ty(ty) { @@ -417,18 +421,18 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty span: spans.into(), note: (), }); - tcx.ty_error(guar) + Ty::new_error(tcx, guar) } _ => icx.to_ty(*self_ty), }, ItemKind::Fn(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id.to_def_id(), substs) + Ty::new_fn_def(tcx, def_id.to_def_id(), substs) } ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => { let def = tcx.adt_def(def_id); let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_adt(def, substs) + Ty::new_adt(tcx, def, substs) } ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias { .. }, @@ -469,10 +473,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty Node::ForeignItem(foreign_item) => match foreign_item.kind { ForeignItemKind::Fn(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id.to_def_id(), substs) + Ty::new_fn_def(tcx, def_id.to_def_id(), substs) } ForeignItemKind::Static(t, _) => icx.to_ty(t), - ForeignItemKind::Type => tcx.mk_foreign(def_id.to_def_id()), + ForeignItemKind::Type => Ty::new_foreign(tcx, def_id.to_def_id()), }, Node::Ctor(def) | Node::Variant(Variant { data: def, .. }) => match def { @@ -481,7 +485,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty } VariantData::Tuple(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id.to_def_id(), substs) + Ty::new_fn_def(tcx, def_id.to_def_id(), substs) } }, diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 4d96a7ff4c3..f4779a3f265 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -84,7 +84,7 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local _ => "item", }, }); - tcx.ty_error(reported) + Ty::new_error(tcx, reported) } } @@ -128,7 +128,8 @@ impl TaitConstraintLocator<'_> { // ``` let tables = self.tcx.typeck(item_def_id); if let Some(guar) = tables.tainted_by_errors { - self.found = Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error(guar) }); + self.found = + Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(self.tcx, guar) }); return; } @@ -162,7 +163,7 @@ impl TaitConstraintLocator<'_> { if let Some(prev) = &mut self.found { if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() { let guar = prev.report_mismatch(&concrete_type, self.def_id, self.tcx).emit(); - prev.ty = self.tcx.ty_error(guar); + prev.ty = Ty::new_error(self.tcx, guar); } } else { self.found = Some(concrete_type); @@ -258,7 +259,7 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>( if let Some(guar) = tables.tainted_by_errors { // Some error in the owner fn prevented us from populating // the `concrete_opaque_types` table. - tcx.ty_error(guar) + Ty::new_error(tcx, guar) } else { // Fall back to the RPIT we inferred during HIR typeck if let Some(hir_opaque_ty) = hir_opaque_ty { @@ -270,7 +271,7 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>( // so we can just make the hidden type be `!`. // For backwards compatibility reasons, we fall back to // `()` until we the diverging default is changed. - tcx.mk_diverging_default() + Ty::new_diverging_default(tcx) } } } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index cb840592edd..205e26d0eda 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -5,7 +5,7 @@ use rustc_errors::{ error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, MultiSpan, }; -use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{self, print::TraitRefPrintOnlyTraitPath, Ty}; use rustc_span::{symbol::Ident, Span, Symbol}; @@ -900,3 +900,11 @@ pub(crate) enum LateBoundInApit { param_span: Span, }, } + +#[derive(LintDiagnostic)] +#[diag(hir_analysis_unused_associated_type_bounds)] +#[note] +pub struct UnusedAssociatedTypeBounds { + #[suggestion(code = "")] + pub span: Span, +} diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 383144ce139..c64fb469bb2 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -77,7 +77,7 @@ use rustc_infer::traits::specialization_graph::Node; use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef}; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{self, translate_substs_with_cause, wf, ObligationCtxt}; @@ -113,7 +113,7 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node let span = tcx.def_span(impl1_def_id); check_has_items(tcx, impl1_def_id, impl2_node, span); - if let Some((impl1_substs, impl2_substs)) = get_impl_substs(tcx, impl1_def_id, impl2_node) { + if let Ok((impl1_substs, impl2_substs)) = get_impl_substs(tcx, impl1_def_id, impl2_node) { let impl2_def_id = impl2_node.def_id(); debug!(?impl2_def_id, ?impl2_substs); @@ -171,16 +171,14 @@ fn get_impl_substs( tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, -) -> Option<(SubstsRef<'_>, SubstsRef<'_>)> { +) -> Result<(SubstsRef<'_>, SubstsRef<'_>), ErrorGuaranteed> { let infcx = &tcx.infer_ctxt().build(); let ocx = ObligationCtxt::new(infcx); let param_env = tcx.param_env(impl1_def_id); - - let assumed_wf_types = - ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id); + let impl1_span = tcx.def_span(impl1_def_id); + let assumed_wf_types = ocx.assumed_wf_types_and_report_errors(param_env, impl1_def_id)?; let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id); - let impl1_span = tcx.def_span(impl1_def_id); let impl2_substs = translate_substs_with_cause( infcx, param_env, @@ -198,8 +196,8 @@ fn get_impl_substs( let errors = ocx.select_all_or_error(); if !errors.is_empty() { - ocx.infcx.err_ctxt().report_fulfillment_errors(&errors); - return None; + let guar = ocx.infcx.err_ctxt().report_fulfillment_errors(&errors); + return Err(guar); } let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, assumed_wf_types); @@ -207,10 +205,10 @@ fn get_impl_substs( let _ = ocx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env); let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else { let span = tcx.def_span(impl1_def_id); - tcx.sess.emit_err(SubstsOnOverriddenImpl { span }); - return None; + let guar = tcx.sess.emit_err(SubstsOnOverriddenImpl { span }); + return Err(guar); }; - Some((impl1_substs, impl2_substs)) + Ok((impl1_substs, impl2_substs)) } /// Returns a list of all of the unconstrained subst of the given impl. @@ -553,7 +551,6 @@ fn trait_predicate_kind<'tcx>( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::Ambiguous - | ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => None, + | ty::PredicateKind::Ambiguous => None, } } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index d2a1b1c1a42..a68832d96a6 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -319,16 +319,19 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { expected_return_type = main_fnsig.output(); } else { // standard () main return type - expected_return_type = ty::Binder::dummy(tcx.mk_unit()); + expected_return_type = ty::Binder::dummy(Ty::new_unit(tcx)); } if error { return; } - let se_ty = tcx.mk_fn_ptr(expected_return_type.map_bound(|expected_return_type| { - tcx.mk_fn_sig([], expected_return_type, false, hir::Unsafety::Normal, Abi::Rust) - })); + let se_ty = Ty::new_fn_ptr( + tcx, + expected_return_type.map_bound(|expected_return_type| { + tcx.mk_fn_sig([], expected_return_type, false, hir::Unsafety::Normal, Abi::Rust) + }), + ); require_same_types( tcx, @@ -339,7 +342,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { ), param_env, se_ty, - tcx.mk_fn_ptr(main_fnsig), + Ty::new_fn_ptr(tcx, main_fnsig), ); } fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { @@ -397,13 +400,16 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { } } - let se_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig( - [tcx.types.isize, tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))], - tcx.types.isize, - false, - hir::Unsafety::Normal, - Abi::Rust, - ))); + let se_ty = Ty::new_fn_ptr( + tcx, + ty::Binder::dummy(tcx.mk_fn_sig( + [tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))], + tcx.types.isize, + false, + hir::Unsafety::Normal, + Abi::Rust, + )), + ); require_same_types( tcx, @@ -414,7 +420,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { ), ty::ParamEnv::empty(), // start should not have any where bounds. se_ty, - tcx.mk_fn_ptr(tcx.fn_sig(start_def_id).subst_identity()), + Ty::new_fn_ptr(tcx, tcx.fn_sig(start_def_id).subst_identity()), ); } _ => { diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index 3a04c3336ca..a7fca41f86a 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -53,8 +53,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { | ty::ClauseKind::Projection(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) - | ty::ClauseKind::TypeWellFormedFromEnv(_) => {} + | ty::ClauseKind::ConstEvaluatable(_) => {} } } diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index c7fa27da1ac..e8720a5da02 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -65,7 +65,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // us to give better error messages (pointing to a usually better // arm for inconsistent arms or to the whole match when a `()` type // is required). - Expectation::ExpectHasType(ety) if ety != self.tcx.mk_unit() => ety, + Expectation::ExpectHasType(ety) if ety != Ty::new_unit(self.tcx) => ety, _ => self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span: expr.span, diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 9da72aae776..f306653c1ab 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -6,8 +6,9 @@ use crate::type_error_struct; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, StashKey}; use rustc_hir as hir; -use rustc_hir::def::{self, CtorKind, Namespace, Res}; +use rustc_hir::def::{self, CtorKind, DefKind, Namespace, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::HirId; use rustc_hir_analysis::autoderef::Autoderef; use rustc_infer::{ infer, @@ -89,7 +90,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => self.check_expr(callee_expr), }; - let expr_ty = self.structurally_resolved_type(call_expr.span, original_callee_ty); + let expr_ty = self.structurally_resolve_type(call_expr.span, original_callee_ty); let mut autoderef = self.autoderef(callee_expr.span, expr_ty); let mut result = None; @@ -138,7 +139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { autoderef: &Autoderef<'a, 'tcx>, ) -> Option<CallStep<'tcx>> { let adjusted_ty = - self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false)); + self.structurally_resolve_type(autoderef.span(), autoderef.final_ty(false)); // If the callee is a bare function or a closure, then we're all set. match *adjusted_ty.kind() { @@ -232,12 +233,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let Some(trait_def_id) = opt_trait_def_id else { continue }; let opt_input_type = opt_arg_exprs.map(|arg_exprs| { - self.tcx.mk_tup_from_iter(arg_exprs.iter().map(|e| { - self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span: e.span, - }) - })) + Ty::new_tup_from_iter( + self.tcx, + arg_exprs.iter().map(|e| { + self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span: e.span, + }) + }), + ) }); if let Some(ok) = self.lookup_method_in_trait( @@ -376,15 +380,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Expectation<'tcx>, ) -> Ty<'tcx> { let (fn_sig, def_id) = match *callee_ty.kind() { - ty::FnDef(def_id, subst) => { - let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, subst); + ty::FnDef(def_id, substs) => { + self.enforce_context_effects(call_expr.hir_id, call_expr.span, def_id, substs); + let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, substs); // Unit testing: function items annotated with // `#[rustc_evaluate_where_clauses]` trigger special output // to let us test the trait evaluation system. if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) { let predicates = self.tcx.predicates_of(def_id); - let predicates = predicates.instantiate(self.tcx, subst); + let predicates = predicates.instantiate(self.tcx, substs); for (predicate, predicate_span) in predicates { let obligation = Obligation::new( self.tcx, @@ -405,6 +410,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } (fn_sig, Some(def_id)) } + // FIXME(effects): these arms should error because we can't enforce them ty::FnPtr(sig) => (sig, None), _ => { for arg in arg_exprs { @@ -432,7 +438,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let err = self.report_invalid_callee(call_expr, callee_expr, callee_ty, arg_exprs); - return self.tcx.ty_error(err); + return Ty::new_error(self.tcx, err); } }; @@ -739,6 +745,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn_sig.output() } + #[tracing::instrument(level = "debug", skip(self, span))] + pub(super) fn enforce_context_effects( + &self, + call_expr_hir: HirId, + span: Span, + callee_did: DefId, + callee_substs: SubstsRef<'tcx>, + ) { + let tcx = self.tcx; + + if !tcx.features().effects || tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you { + return; + } + + // Compute the constness required by the context. + let context = tcx.hir().enclosing_body_owner(call_expr_hir); + let const_context = tcx.hir().body_const_context(context); + + let kind = tcx.def_kind(context.to_def_id()); + debug_assert_ne!(kind, DefKind::ConstParam); + + if tcx.has_attr(context.to_def_id(), sym::rustc_do_not_const_check) { + trace!("do not const check this context"); + return; + } + + let effect = match const_context { + Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => tcx.consts.false_, + Some(hir::ConstContext::ConstFn) => { + let substs = ty::InternalSubsts::identity_for_item(tcx, context); + substs.host_effect_param().expect("ConstContext::Maybe must have host effect param") + } + None => tcx.consts.true_, + }; + + let generics = tcx.generics_of(callee_did); + + trace!(?effect, ?generics, ?callee_substs); + + if let Some(idx) = generics.host_effect_index { + let param = callee_substs.const_at(idx); + let cause = self.misc(span); + match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::No, effect, param) { + Ok(infer::InferOk { obligations, value: () }) => { + self.register_predicates(obligations); + } + Err(e) => { + // FIXME(effects): better diagnostic + self.err_ctxt().report_mismatched_consts(&cause, effect, param, e).emit(); + } + } + } + } + fn confirm_overloaded_call( &self, call_expr: &'tcx hir::Expr<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 7a1e830073a..71799387458 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -393,7 +393,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { && fcx .try_coerce( self.expr, - fcx.tcx.mk_ref( + Ty::new_ref(fcx.tcx, fcx.tcx.lifetimes.re_erased, TypeAndMut { ty: expr_ty, mutbl }, ), @@ -410,7 +410,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { && fcx .try_coerce( self.expr, - fcx.tcx.mk_ref( + Ty::new_ref(fcx.tcx, expr_reg, TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut }, ), @@ -428,7 +428,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { && fcx .try_coerce( self.expr, - fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }), + Ty::new_ref(fcx.tcx,reg, TypeAndMut { ty: self.expr_ty, mutbl }), self.cast_ty, AllowTwoPhase::No, None, @@ -441,7 +441,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { && fcx .try_coerce( self.expr, - fcx.tcx.mk_ref( + Ty::new_ref(fcx.tcx, fcx.tcx.lifetimes.re_erased, TypeAndMut { ty: self.expr_ty, mutbl }, ), @@ -717,8 +717,8 @@ impl<'a, 'tcx> CastCheck<'tcx> { #[instrument(skip(fcx), level = "debug")] pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) { - self.expr_ty = fcx.structurally_resolved_type(self.expr_span, self.expr_ty); - self.cast_ty = fcx.structurally_resolved_type(self.cast_span, self.cast_ty); + self.expr_ty = fcx.structurally_resolve_type(self.expr_span, self.expr_ty); + self.cast_ty = fcx.structurally_resolve_type(self.cast_span, self.cast_ty); debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty); @@ -765,7 +765,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { let res = fcx.try_coerce( self.expr, self.expr_ty, - fcx.tcx.mk_fn_ptr(f), + Ty::new_fn_ptr(fcx.tcx, f), AllowTwoPhase::No, None, ); @@ -957,7 +957,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // from a region pointer to a vector. // Coerce to a raw pointer so that we generate AddressOf in MIR. - let array_ptr_type = fcx.tcx.mk_ptr(m_expr); + let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr); fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None) .unwrap_or_else(|_| { bug!( diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 0a1b639af51..8b57e311fc0 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -62,11 +62,11 @@ pub(super) fn check_fn<'a, 'tcx>( fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); yield_ty } else { - tcx.mk_unit() + Ty::new_unit(tcx,) }; // Resume type defaults to `()` if the generator has no argument. - let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit()); + let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| Ty::new_unit(tcx,)); fcx.resume_yield_tys = Some((resume_ty, yield_ty)); } @@ -256,10 +256,10 @@ fn check_lang_start_fn<'tcx>( // for example `start`'s generic should be a type parameter let generics = tcx.generics_of(def_id); let fn_generic = generics.param_at(0, tcx); - let generic_ty = tcx.mk_ty_param(fn_generic.index, fn_generic.name); + let generic_ty = Ty::new_param(tcx, fn_generic.index, fn_generic.name); let expected_fn_sig = tcx.mk_fn_sig([], generic_ty, false, hir::Unsafety::Normal, Abi::Rust); - let expected_ty = tcx.mk_fn_ptr(Binder::dummy(expected_fn_sig)); + let expected_ty = Ty::new_fn_ptr(tcx, Binder::dummy(expected_fn_sig)); // we emit the same error to suggest changing the arg no matter what's wrong with the arg let emit_main_fn_arg_err = || { @@ -316,9 +316,9 @@ fn check_lang_start_fn<'tcx>( if !argv_is_okay { let inner_ptr_ty = - tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: tcx.types.u8 }); + Ty::new_ptr(tcx, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: tcx.types.u8 }); let expected_ty = - tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: inner_ptr_ty }); + Ty::new_ptr(tcx, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: inner_ptr_ty }); tcx.sess.emit_err(LangStartIncorrectParam { param_span: decl.inputs[2].span, param_num: 3, diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index c64b64e925a..78a9ac49de2 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -117,7 +117,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, ); - return self.tcx.mk_generator( + return Ty::new_generator( + self.tcx, expr_def_id.to_def_id(), generator_substs.substs, movability, @@ -128,7 +129,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // the `closures` table. let sig = bound_sig.map_bound(|sig| { self.tcx.mk_fn_sig( - [self.tcx.mk_tup(sig.inputs())], + [Ty::new_tup(self.tcx, sig.inputs())], sig.output(), sig.c_variadic, sig.unsafety, @@ -155,12 +156,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::ClosureSubstsParts { parent_substs, closure_kind_ty, - closure_sig_as_fn_ptr_ty: self.tcx.mk_fn_ptr(sig), + closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(self.tcx, sig), tupled_upvars_ty, }, ); - self.tcx.mk_closure(expr_def_id.to_def_id(), closure_substs.substs) + Ty::new_closure(self.tcx, expr_def_id.to_def_id(), closure_substs.substs) } /// Given the expected type, figures out what it can about this closure we @@ -190,7 +191,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (sig, kind) } ty::Infer(ty::TyVar(vid)) => self.deduce_closure_signature_from_predicates( - self.tcx.mk_ty_var(self.root_var(vid)), + Ty::new_var(self.tcx, self.root_var(vid)), self.obligations_for_self_ty(vid).map(|obl| (obl.predicate, obl.cause.span)), ), ty::FnPtr(sig) => { @@ -806,7 +807,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { guar: ErrorGuaranteed, ) -> ty::PolyFnSig<'tcx> { let astconv: &dyn AstConv<'_> = self; - let err_ty = self.tcx.ty_error(guar); + let err_ty = Ty::new_error(self.tcx, guar); let supplied_arguments = decl.inputs.iter().map(|a| { // Convert the types that the user supplied (if any), but ignore them. diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 5f98bacaf2a..ea6ae094f09 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -192,7 +192,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let _ = self.commit_if_ok(|_| { self.at(&self.cause, self.param_env).eq(DefineOpaqueTypes::Yes, a, b) }); - return success(vec![], self.fcx.tcx.ty_error(guar), vec![]); + return success(vec![], Ty::new_error(self.fcx.tcx, guar), vec![]); } // Coercing from `!` to any type is allowed: @@ -440,7 +440,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } r_borrow_var.unwrap() }; - let derefd_ty_a = self.tcx.mk_ref( + let derefd_ty_a = Ty::new_ref( + self.tcx, r, TypeAndMut { ty: referent_ty, @@ -558,9 +559,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Adjustment { kind: Adjust::Deref(None), target: ty_a }, Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mutbl)), - target: self - .tcx - .mk_ref(r_borrow, ty::TypeAndMut { mutbl: mutbl_b, ty: ty_a }), + target: Ty::new_ref( + self.tcx, + r_borrow, + ty::TypeAndMut { mutbl: mutbl_b, ty: ty_a }, + ), }, )) } @@ -571,7 +574,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Adjustment { kind: Adjust::Deref(None), target: ty_a }, Adjustment { kind: Adjust::Borrow(AutoBorrow::RawPtr(mt_b)), - target: self.tcx.mk_ptr(ty::TypeAndMut { mutbl: mt_b, ty: ty_a }), + target: Ty::new_ptr(self.tcx, ty::TypeAndMut { mutbl: mt_b, ty: ty_a }), }, )) } @@ -883,7 +886,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.at(&self.cause, self.param_env).normalize(a_sig); obligations.extend(o1); - let a_fn_pointer = self.tcx.mk_fn_ptr(a_sig); + let a_fn_pointer = Ty::new_fn_ptr(self.tcx, a_sig); let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn( a_fn_pointer, a_sig, @@ -945,7 +948,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let closure_sig = substs_a.as_closure().sig(); let unsafety = fn_ty.unsafety(); let pointer_ty = - self.tcx.mk_fn_ptr(self.tcx.signature_unclosure(closure_sig, unsafety)); + Ty::new_fn_ptr(self.tcx, self.tcx.signature_unclosure(closure_sig, unsafety)); debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty); self.unify_and( pointer_ty, @@ -973,7 +976,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { coerce_mutbls(mt_a.mutbl, mutbl_b)?; // Check that the types which they point at are compatible. - let a_unsafe = self.tcx.mk_ptr(ty::TypeAndMut { mutbl: mutbl_b, ty: mt_a.ty }); + let a_unsafe = Ty::new_ptr(self.tcx, ty::TypeAndMut { mutbl: mutbl_b, ty: mt_a.ty }); // Although references and unsafe ptrs have the same // representation, we still register an Adjust::DerefRef so that // regionck knows that the region for `a` must be valid here. @@ -1005,7 +1008,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { allow_two_phase: AllowTwoPhase, cause: Option<ObligationCause<'tcx>>, ) -> RelateResult<'tcx, Ty<'tcx>> { - let source = self.resolve_vars_with_obligations(expr_ty); + let source = self.try_structurally_resolve_type(expr.span, expr_ty); debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); let cause = @@ -1015,7 +1018,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (adjustments, _) = self.register_infer_ok_obligations(ok); self.apply_adjustments(expr, adjustments); - Ok(if let Err(guar) = expr_ty.error_reported() { self.tcx.ty_error(guar) } else { target }) + Ok(if let Err(guar) = expr_ty.error_reported() { + Ty::new_error(self.tcx, guar) + } else { + target + }) } /// Same as `try_coerce()`, but without side-effects. @@ -1179,7 +1186,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map(|ok| self.register_infer_ok_obligations(ok))?; // Reify both sides and return the reified fn pointer type. - let fn_ptr = self.tcx.mk_fn_ptr(sig); + let fn_ptr = Ty::new_fn_ptr(self.tcx, sig); let prev_adjustment = match prev_ty.kind() { ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(a_sig.unsafety())), ty::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer), @@ -1430,7 +1437,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fcx, cause, None, - fcx.tcx.mk_unit(), + Ty::new_unit(fcx.tcx), Some(augment_error), label_unit_as_expected, ) @@ -1461,7 +1468,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { // If we see any error types, just propagate that error // upwards. if let Err(guar) = (expression_ty, self.merged_ty()).error_reported() { - self.final_ty = Some(fcx.tcx.ty_error(guar)); + self.final_ty = Some(Ty::new_error(fcx.tcx, guar)); return; } @@ -1649,7 +1656,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { let reported = err.emit_unless(unsized_return); - self.final_ty = Some(fcx.tcx.ty_error(reported)); + self.final_ty = Some(Ty::new_error(fcx.tcx, reported)); } } } diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 47f3c6b8407..cc8198aab25 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -1366,10 +1366,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // ``` let ref_ty = match mutability { hir::Mutability::Mut => { - self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, checked_ty) + Ty::new_mut_ref(self.tcx,self.tcx.lifetimes.re_static, checked_ty) } hir::Mutability::Not => { - self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, checked_ty) + Ty::new_imm_ref(self.tcx,self.tcx.lifetimes.re_static, checked_ty) } }; if self.can_coerce(ref_ty, expected) { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index f5be030c1a5..72b29f7b6e9 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -94,7 +94,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &adjustments[..] { target.to_owned() } else { - self.tcx().ty_error(reported) + Ty::new_error(self.tcx(), reported) }; } @@ -321,7 +321,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.types.never } else { // There was an error; make type-check fail. - tcx.ty_error_misc() + Ty::new_misc_error(tcx) } } ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr), @@ -361,7 +361,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Field(base, field) => self.check_field(expr, &base, field, expected), ExprKind::Index(base, idx) => self.check_expr_index(base, idx, expr), ExprKind::Yield(value, ref src) => self.check_expr_yield(value, expr, src), - hir::ExprKind::Err(guar) => tcx.ty_error(guar), + hir::ExprKind::Err(guar) => Ty::new_error(tcx, guar), } } @@ -380,7 +380,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut oprnd_t = self.check_expr_with_expectation(&oprnd, expected_inner); if !oprnd_t.references_error() { - oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t); + oprnd_t = self.structurally_resolve_type(expr.span, oprnd_t); match unop { hir::UnOp::Deref => { if let Some(ty) = self.lookup_derefing(expr, oprnd, oprnd_t) { @@ -399,7 +399,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } - oprnd_t = tcx.ty_error(err.emit()); + oprnd_t = Ty::new_error(tcx, err.emit()); } } hir::UnOp::Not => { @@ -449,10 +449,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tm = ty::TypeAndMut { ty, mutbl }; match kind { - _ if tm.ty.references_error() => self.tcx.ty_error_misc(), + _ if tm.ty.references_error() => Ty::new_misc_error(self.tcx), hir::BorrowKind::Raw => { self.check_named_place_expr(oprnd); - self.tcx.mk_ptr(tm) + Ty::new_ptr(self.tcx, tm) } hir::BorrowKind::Ref => { // Note: at this point, we cannot say what the best lifetime @@ -470,7 +470,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // whose address was taken can actually be made to live as long // as it needs to live. let region = self.next_region_var(infer::AddrOfRegion(expr.span)); - self.tcx.mk_ref(region, tm) + Ty::new_ref(self.tcx, region, tm) } } } @@ -528,11 +528,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let e = self.tcx.sess.delay_span_bug(qpath.span(), "`Res::Err` but no error emitted"); self.set_tainted_by_errors(e); - tcx.ty_error(e) + Ty::new_error(tcx, e) } Res::Def(DefKind::Variant, _) => { let e = report_unexpected_variant_res(tcx, res, qpath, expr.span, "E0533", "value"); - tcx.ty_error(e) + Ty::new_error(tcx, e) } _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0, }; @@ -620,7 +620,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(ctxt) => ctxt.coerce.as_ref().map(|coerce| coerce.expected_ty()), None => { // Avoid ICE when `break` is inside a closure (#65383). - return tcx.ty_error_with_message( + return Ty::new_error_with_message( + tcx, expr.span, "break was outside loop, but no error was emitted", ); @@ -631,7 +632,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the loop context is not a `loop { }`, then break with // a value is illegal, and `opt_coerce_to` will be `None`. // Just set expectation to error in that case. - let coerce_to = opt_coerce_to.unwrap_or_else(|| tcx.ty_error_misc()); + let coerce_to = opt_coerce_to.unwrap_or_else(|| Ty::new_misc_error(tcx)); // Recurse without `enclosing_breakables` borrowed. e_ty = self.check_expr_with_hint(e, coerce_to); @@ -639,7 +640,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { // Otherwise, this is a break *without* a value. That's // always legal, and is equivalent to `break ()`. - e_ty = tcx.mk_unit(); + e_ty = Ty::new_unit(tcx); cause = self.misc(expr.span); } @@ -649,7 +650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); let Some(ctxt) = enclosing_breakables.opt_find_breakable(target_id) else { // Avoid ICE when `break` is inside a closure (#65383). - return tcx.ty_error_with_message( + return Ty::new_error_with_message(tcx, expr.span, "break was outside loop, but no error was emitted", ); @@ -707,7 +708,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // this can only happen if the `break` was not // inside a loop at all, which is caught by the // loop-checking pass. - let err = self.tcx.ty_error_with_message( + let err = Ty::new_error_with_message( + self.tcx, expr.span, "break was outside loop, but no error was emitted", ); @@ -1072,7 +1074,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let result_ty = coerce.complete(self); - if let Err(guar) = cond_ty.error_reported() { self.tcx.ty_error(guar) } else { result_ty } + if let Err(guar) = cond_ty.error_reported() { + Ty::new_error(self.tcx, guar) + } else { + result_ty + } } /// Type check assignment expression `expr` of form `lhs = rhs`. @@ -1090,7 +1096,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // The expected type is `bool` but this will result in `()` so we can reasonably // say that the user intended to write `lhs == rhs` instead of `lhs = rhs`. // The likely cause of this is `if foo = bar { .. }`. - let actual_ty = self.tcx.mk_unit(); + let actual_ty = Ty::new_unit(self.tcx); let mut err = self.demand_suptype_diag(expr.span, expected_ty, actual_ty).unwrap(); let lhs_ty = self.check_expr(&lhs); let rhs_ty = self.check_expr(&rhs); @@ -1148,7 +1154,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the assignment expression itself is ill-formed, don't // bother emitting another error let reported = err.emit_unless(lhs_ty.references_error() || rhs_ty.references_error()); - return self.tcx.ty_error(reported); + return Ty::new_error(self.tcx, reported); } let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace); @@ -1195,9 +1201,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized); if let Err(guar) = (lhs_ty, rhs_ty).error_reported() { - self.tcx.ty_error(guar) + Ty::new_error(self.tcx, guar) } else { - self.tcx.mk_unit() + Ty::new_unit(self.tcx) } } @@ -1252,7 +1258,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // [1] self.tcx.sess.delay_span_bug(body.span, "no coercion, but loop may not break"); } - ctxt.coerce.map(|c| c.complete(self)).unwrap_or_else(|| self.tcx.mk_unit()) + ctxt.coerce.map(|c| c.complete(self)).unwrap_or_else(|| Ty::new_unit(self.tcx)) } /// Checks a method call. @@ -1266,14 +1272,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let rcvr_t = self.check_expr(&rcvr); // no need to check for bot/err -- callee does that - let rcvr_t = self.structurally_resolved_type(rcvr.span, rcvr_t); + let rcvr_t = self.structurally_resolve_type(rcvr.span, rcvr_t); let span = segment.ident.span; let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) { Ok(method) => { // We could add a "consider `foo::<params>`" suggestion here, but I wasn't able to - // trigger this codepath causing `structurally_resolved_type` to emit an error. + // trigger this codepath causing `structurally_resolve_type` to emit an error. + self.enforce_context_effects(expr.hir_id, expr.span, method.def_id, method.substs); self.write_method_call(expr.hir_id, method); Ok(method) } @@ -1315,7 +1322,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Eagerly check for some obvious errors. if let Err(guar) = (t_expr, t_cast).error_reported() { - self.tcx.ty_error(guar) + Ty::new_error(self.tcx, guar) } else { // Defer other checks until we're done type checking. let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); @@ -1336,7 +1343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { deferred_cast_checks.push(cast_check); t_cast } - Err(guar) => self.tcx.ty_error(guar), + Err(guar) => Ty::new_error(self.tcx, guar), } } } @@ -1376,7 +1383,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let array_len = args.len() as u64; self.suggest_array_len(expr, array_len); - self.tcx.mk_array(element_ty, array_len) + Ty::new_array(self.tcx, element_ty, array_len) } fn suggest_array_len(&self, expr: &'tcx hir::Expr<'tcx>, array_len: u64) { @@ -1464,18 +1471,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let Err(guar) = element_ty.error_reported() { - return tcx.ty_error(guar); + return Ty::new_error(tcx, guar); } self.check_repeat_element_needs_copy_bound(element, count, element_ty); self.register_wf_obligation( - tcx.mk_array_with_const_len(t, count).into(), + Ty::new_array_with_const_len(tcx, t, count).into(), expr.span, traits::WellFormed(None), ); - tcx.mk_array_with_const_len(t, count) + Ty::new_array_with_const_len(tcx, t, count) } fn check_repeat_element_needs_copy_bound( @@ -1538,9 +1545,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } _ => self.check_expr_with_expectation(&e, NoExpectation), }); - let tuple = self.tcx.mk_tup_from_iter(elt_ts_iter); + let tuple = Ty::new_tup_from_iter(self.tcx, elt_ts_iter); if let Err(guar) = tuple.error_reported() { - self.tcx.ty_error(guar) + Ty::new_error(self.tcx, guar) } else { self.require_type_is_sized(tuple, expr.span, traits::TupleInitializerSized); tuple @@ -1560,7 +1567,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(data) => data, Err(guar) => { self.check_struct_fields_on_error(fields, base_expr); - return self.tcx.ty_error(guar); + return Ty::new_error(self.tcx, guar); } }; @@ -1659,7 +1666,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) }; - tcx.ty_error(guar) + Ty::new_error(tcx, guar) }; // Make sure to give a type to the field even if there's @@ -1771,7 +1778,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `MyStruct<'a, _, F2, C>`, as opposed to just `_`... // This is important to allow coercions to happen in // `other_struct` itself. See `coerce-in-base-expr.rs`. - let fresh_base_ty = self.tcx.mk_adt(*adt, fresh_substs); + let fresh_base_ty = Ty::new_adt(self.tcx, *adt, fresh_substs); self.check_expr_has_type_or_error( base_expr, self.resolve_vars_if_possible(fresh_base_ty), @@ -2252,7 +2259,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { debug!("check_field(expr: {:?}, base: {:?}, field: {:?})", expr, base, field); let base_ty = self.check_expr(base); - let base_ty = self.structurally_resolved_type(base.span, base_ty); + let base_ty = self.structurally_resolve_type(base.span, base_ty); let mut private_candidate = None; let mut autoderef = self.autoderef(expr.span, base_ty); while let Some((deref_base_ty, _)) = autoderef.next() { @@ -2300,7 +2307,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => {} } } - self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false)); + self.structurally_resolve_type(autoderef.span(), autoderef.final_ty(false)); if let Some((adjustments, did)) = private_candidate { // (#90483) apply adjustments to avoid ExprUseVisitor from @@ -2313,7 +2320,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { did, expected.only_has_type(self), ); - return self.tcx().ty_error(guar); + return Ty::new_error(self.tcx(), guar); } let guar = if field.name == kw::Empty { @@ -2399,7 +2406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.emit() }; - self.tcx().ty_error(guar) + Ty::new_error(self.tcx(), guar) } fn suggest_await_on_field_access( @@ -2857,7 +2864,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else if idx_t.references_error() { idx_t } else { - let base_t = self.structurally_resolved_type(base.span, base_t); + let base_t = self.structurally_resolve_type(base.span, base_t); match self.lookup_indexing(expr, base, base_t, idx, idx_t) { Some((index_ty, element_ty)) => { // two-phase not needed because index_ty is never mutable @@ -2931,7 +2938,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let reported = err.emit(); - self.tcx.ty_error(reported) + Ty::new_error(self.tcx, reported) } } } @@ -3005,7 +3012,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let element_ty = ocx.normalize( &cause, self.param_env, - self.tcx.mk_projection(index_trait_output_def_id, impl_trait_ref.substs), + Ty::new_projection(self.tcx, index_trait_output_def_id, impl_trait_ref.substs), ); let errors = ocx.select_where_possible(); @@ -3053,14 +3060,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // information. Hence, we check the source of the yield expression here and check its // value's type against `()` (this check should always hold). None if src.is_await() => { - self.check_expr_coercible_to_type(&value, self.tcx.mk_unit(), None); - self.tcx.mk_unit() + self.check_expr_coercible_to_type(&value, Ty::new_unit(self.tcx), None); + Ty::new_unit(self.tcx) } _ => { self.tcx.sess.emit_err(YieldExprOutsideOfGenerator { span: expr.span }); // Avoid expressions without types during writeback (#78653). self.check_expr(value); - self.tcx.mk_unit() + Ty::new_unit(self.tcx) } } } @@ -3084,14 +3091,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // allows them to be inferred based on how they are used later in the // function. if is_input { - let ty = self.structurally_resolved_type(expr.span, ty); + let ty = self.structurally_resolve_type(expr.span, ty); match *ty.kind() { ty::FnDef(..) => { - let fnptr_ty = self.tcx.mk_fn_ptr(ty.fn_sig(self.tcx)); + let fnptr_ty = Ty::new_fn_ptr(self.tcx, ty.fn_sig(self.tcx)); self.demand_coerce(expr, ty, fnptr_ty, None, AllowTwoPhase::No); } ty::Ref(_, base_ty, mutbl) => { - let ptr_ty = self.tcx.mk_ptr(ty::TypeAndMut { ty: base_ty, mutbl }); + let ptr_ty = Ty::new_ptr(self.tcx, ty::TypeAndMut { ty: base_ty, mutbl }); self.demand_coerce(expr, ty, ptr_ty, None, AllowTwoPhase::No); } _ => {} @@ -3126,7 +3133,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if asm.options.contains(ast::InlineAsmOptions::NORETURN) { self.tcx.types.never } else { - self.tcx.mk_unit() + Ty::new_unit(self.tcx) } } @@ -3142,7 +3149,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut current_container = container; for &field in fields { - let container = self.structurally_resolved_type(expr.span, current_container); + let container = self.structurally_resolve_type(expr.span, current_container); match container.kind() { ty::Adt(container_def, substs) if !container_def.is_enum() => { diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index b7ae621c685..a76db6e73a1 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -104,7 +104,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // type, `?T` is not considered unsolved, but `?I` is. The // same is true for float variables.) let fallback = match ty.kind() { - _ if let Some(e) = self.tainted_by_errors() => self.tcx.ty_error(e), + _ if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx,e), ty::Infer(ty::IntVar(_)) => self.tcx.types.i32, ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64, _ => match diverging_fallback.get(&ty) { @@ -287,7 +287,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { let mut diverging_fallback = FxHashMap::default(); diverging_fallback.reserve(diverging_vids.len()); for &diverging_vid in &diverging_vids { - let diverging_ty = self.tcx.mk_ty_var(diverging_vid); + let diverging_ty = Ty::new_var(self.tcx, diverging_vid); let root_vid = self.root_var(diverging_vid); let can_reach_non_diverging = coercion_graph .depth_first_search(root_vid) @@ -334,7 +334,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { diverging_fallback.insert(diverging_ty, self.tcx.types.unit); } else { debug!("fallback to ! - all diverging: {:?}", diverging_vid); - diverging_fallback.insert(diverging_ty, self.tcx.mk_diverging_default()); + diverging_fallback.insert(diverging_ty, Ty::new_diverging_default(self.tcx)); } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 0ee87173a36..9a80a9c9303 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -83,6 +83,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// version (resolve_vars_if_possible), this version will /// also select obligations if it seems useful, in an effort /// to get more type information. + // FIXME(-Ztrait-solver=next): A lot of the calls to this method should + // probably be `try_structurally_resolve_type` or `structurally_resolve_type` instead. pub(in super::super) fn resolve_vars_with_obligations(&self, ty: Ty<'tcx>) -> Ty<'tcx> { self.resolve_vars_with_obligations_and_mutate_fulfillment(ty, |_| {}) } @@ -451,7 +453,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { match self.typeck_results.borrow().node_types().get(id) { Some(&t) => t, - None if let Some(e) = self.tainted_by_errors() => self.tcx.ty_error(e), + None if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx,e), None => { bug!( "no type for node {} in fcx {}", @@ -465,7 +467,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn node_ty_opt(&self, id: hir::HirId) -> Option<Ty<'tcx>> { match self.typeck_results.borrow().node_types().get(id) { Some(&t) => Some(t), - None if let Some(e) = self.tainted_by_errors() => Some(self.tcx.ty_error(e)), + None if let Some(e) = self.tainted_by_errors() => Some(Ty::new_error(self.tcx,e)), None => None, } } @@ -556,7 +558,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx, self.tcx.typeck_root_def_id(expr_def_id.to_def_id()), ); - let witness = self.tcx.mk_generator_witness_mir(expr_def_id.to_def_id(), substs); + let witness = Ty::new_generator_witness_mir(self.tcx, expr_def_id.to_def_id(), substs); // Unify `interior` with `witness` and collect all the resulting obligations. let span = self.tcx.hir().body(body_id).value.span; @@ -683,7 +685,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // inference variable. | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Ambiguous - | ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => None, + => None, }, ) } @@ -701,7 +703,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub(in super::super) fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> { - let ty_error = self.tcx.ty_error_misc(); + let ty_error = Ty::new_misc_error(self.tcx); vec![ty_error; len] } @@ -1240,7 +1242,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } let reported = err.emit(); - return (tcx.ty_error(reported), res); + return (Ty::new_error(tcx, reported), res); } } } else { @@ -1465,16 +1467,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - /// Resolves `typ` by a single level if `typ` is a type variable. + /// Try to resolve `ty` to a structural type, normalizing aliases. /// - /// When the new solver is enabled, this will also attempt to normalize - /// the type if it's a projection (note that it will not deeply normalize - /// projections within the type, just the outermost layer of the type). - /// - /// If no resolution is possible, then an error is reported. - /// Numeric inference variables may be left unresolved. - pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - let mut ty = self.resolve_vars_with_obligations(ty); + /// In case there is still ambiguity, the returned type may be an inference + /// variable. This is different from `structurally_resolve_type` which errors + /// in this case. + pub fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + let ty = self.resolve_vars_with_obligations(ty); if self.next_trait_solver() && let ty::Alias(ty::Projection, _) = ty.kind() @@ -1483,15 +1482,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .at(&self.misc(sp), self.param_env) .structurally_normalize(ty, &mut **self.fulfillment_cx.borrow_mut()) { - Ok(normalized_ty) => { - ty = normalized_ty; - }, + Ok(normalized_ty) => normalized_ty, Err(errors) => { let guar = self.err_ctxt().report_fulfillment_errors(&errors); - return self.tcx.ty_error(guar); + return Ty::new_error(self.tcx,guar); } } - } + } else { + ty + } + } + + /// Resolves `ty` by a single level if `ty` is a type variable. + /// + /// When the new solver is enabled, this will also attempt to normalize + /// the type if it's a projection (note that it will not deeply normalize + /// projections within the type, just the outermost layer of the type). + /// + /// If no resolution is possible, then an error is reported. + /// Numeric inference variables may be left unresolved. + pub fn structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + let ty = self.try_structurally_resolve_type(sp, ty); if !ty.is_ty_var() { ty @@ -1501,7 +1512,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .emit_inference_failure_err(self.body_id, sp, ty.into(), E0282, true) .emit() }); - let err = self.tcx.ty_error(e); + let err = Ty::new_error(self.tcx, e); self.demand_suptype(sp, err, ty); err } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index 223aedefea3..ed9bb4945af 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -254,7 +254,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { type BreakTy = ty::GenericArg<'tcx>; fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> { if let Some(origin) = self.0.type_var_origin(ty) - && let rustc_infer::infer::type_variable::TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) = + && let rustc_infer::infer::type_variable::TypeVariableOriginKind::TypeParameterDefinition(_, def_id) = origin.kind && let generics = self.0.tcx.generics_of(self.1) && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index dacd5559c71..4bd4f2d7e9c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -73,7 +73,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.typeck_results.borrow().expr_ty_adjusted(expr); let ty = self.resolve_vars_if_possible(ty); if ty.has_non_region_infer() { - self.tcx.ty_error_misc() + Ty::new_misc_error(self.tcx) } else { self.tcx.erase_regions(ty) } @@ -101,7 +101,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let err_inputs = match tuple_arguments { DontTupleArguments => err_inputs, - TupleArguments => vec![self.tcx.mk_tup(&err_inputs)], + TupleArguments => vec![Ty::new_tup(self.tcx, &err_inputs)], }; self.check_argument_types( @@ -114,7 +114,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tuple_arguments, method.ok().map(|method| method.def_id), ); - return self.tcx.ty_error_misc(); + return Ty::new_misc_error(self.tcx); } let method = method.unwrap(); @@ -184,7 +184,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the arguments should be wrapped in a tuple (ex: closures), unwrap them here let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments { - let tuple_type = self.structurally_resolved_type(call_span, formal_input_tys[0]); + let tuple_type = self.structurally_resolve_type(call_span, formal_input_tys[0]); match tuple_type.kind() { // We expected a tuple and got a tuple ty::Tuple(arg_types) => { @@ -412,7 +412,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // There are a few types which get autopromoted when passed via varargs // in C but we just error out instead and require explicit casts. - let arg_ty = self.structurally_resolved_type(arg.span, arg_ty); + let arg_ty = self.structurally_resolve_type(arg.span, arg_ty); match arg_ty.kind() { ty::Float(ty::FloatTy::F32) => { variadic_error(tcx.sess, arg.span, arg_ty, "c_double"); @@ -424,7 +424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variadic_error(tcx.sess, arg.span, arg_ty, "c_uint"); } ty::FnDef(..) => { - let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx)); + let ptr_ty = Ty::new_fn_ptr(self.tcx, arg_ty.fn_sig(self.tcx)); let ptr_ty = self.resolve_vars_if_possible(ptr_ty); variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string()); } @@ -539,7 +539,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .typeck_results .borrow() .expr_ty_adjusted_opt(*expr) - .unwrap_or_else(|| tcx.ty_error_misc()); + .unwrap_or_else(|| Ty::new_misc_error(tcx)); (self.resolve_vars_if_possible(ty), normalize_span(expr.span)) }) .collect(); @@ -648,7 +648,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len() { // Wrap up the N provided arguments starting at this position in a tuple. - let provided_as_tuple = tcx.mk_tup_from_iter( + let provided_as_tuple = Ty::new_tup_from_iter(tcx, provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx).take(tys.len()), ); @@ -1309,14 +1309,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; match lit.node { - ast::LitKind::Str(..) => tcx.mk_static_str(), - ast::LitKind::ByteStr(ref v, _) => { - tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.u8, v.len() as u64)) - } + ast::LitKind::Str(..) => Ty::new_static_str(tcx), + ast::LitKind::ByteStr(ref v, _) => Ty::new_imm_ref( + tcx, + tcx.lifetimes.re_static, + Ty::new_array(tcx, tcx.types.u8, v.len() as u64), + ), ast::LitKind::Byte(_) => tcx.types.u8, ast::LitKind::Char(_) => tcx.types.char, - ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(ty::int_ty(t)), - ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(ty::uint_ty(t)), + ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => Ty::new_int(tcx, ty::int_ty(t)), + ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => Ty::new_uint(tcx, ty::uint_ty(t)), ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { ty::Int(_) | ty::Uint(_) => Some(ty), @@ -1328,7 +1330,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { opt_ty.unwrap_or_else(|| self.next_int_var()) } ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => { - tcx.mk_mach_float(ty::float_ty(t)) + Ty::new_float(tcx, ty::float_ty(t)) } ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => { let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { @@ -1338,12 +1340,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { opt_ty.unwrap_or_else(|| self.next_float_var()) } ast::LitKind::Bool(_) => tcx.types.bool, - ast::LitKind::CStr(_, _) => tcx.mk_imm_ref( + ast::LitKind::CStr(_, _) => Ty::new_imm_ref( + tcx, tcx.lifetimes.re_static, tcx.type_of(tcx.require_lang_item(hir::LangItem::CStr, Some(lit.span))) .skip_binder(), ), - ast::LitKind::Err => tcx.ty_error_misc(), + ast::LitKind::Err => Ty::new_misc_error(tcx), } } @@ -1513,7 +1516,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::StmtKind::Item(_) => {} hir::StmtKind::Expr(ref expr) => { // Check with expected type of `()`. - self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| { + self.check_expr_has_type_or_error(&expr, Ty::new_unit(self.tcx), |err| { if expr.can_have_side_effects() { self.suggest_semicolon_at_end(expr.span, err); } @@ -1536,7 +1539,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) { - let unit = self.tcx.mk_unit(); + let unit = Ty::new_unit(self.tcx); let ty = self.check_block_with_expected(blk, ExpectHasType(unit)); // if the block produces a `!` value, that can always be @@ -1649,7 +1652,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { blk.span, blk.hir_id, expected_ty, - self.tcx.mk_unit(), + Ty::new_unit(self.tcx), ); } if !self.consider_removing_semicolon(blk, expected_ty, err) { @@ -1795,7 +1798,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { if let Err(guar) = ty.error_reported() { // Override the types everywhere with `err()` to avoid knock on errors. - let err = self.tcx.ty_error(guar); + let err = Ty::new_error(self.tcx, guar); self.write_ty(hir_id, err); self.write_ty(pat.hir_id, err); self.locals.borrow_mut().insert(hir_id, err); @@ -1823,8 +1826,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let result = self .astconv() .associated_path_to_ty(hir_id, path_span, ty.raw, qself, segment, true); - let ty = - result.map(|(ty, _, _)| ty).unwrap_or_else(|guar| self.tcx().ty_error(guar)); + let ty = result + .map(|(ty, _, _)| ty) + .unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar)); let ty = self.handle_raw_ty(path_span, ty); let result = result.map(|(_, kind, def_id)| (kind, def_id)); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index e035d233bf7..20b34df99b2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -191,7 +191,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn next_root_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - self.tcx.mk_ty_var(self.next_ty_var_id_in_universe(origin, ty::UniverseIndex::ROOT)) + Ty::new_var(self.tcx, self.next_ty_var_id_in_universe(origin, ty::UniverseIndex::ROOT)) } } @@ -295,7 +295,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { trait_ref.substs, ); - self.tcx().mk_projection(item_def_id, item_substs) + Ty::new_projection(self.tcx(), item_def_id, item_substs) } fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 3a4fe334f88..79a7c016185 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -426,7 +426,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Given `Result<_, E>`, check our expected ty is `Result<_, &E>` for // `as_ref` and `as_deref` compatibility. let error_tys_equate_as_ref = error_tys.map_or(true, |(found, expected)| { - self.can_eq(self.param_env, self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, found), expected) + self.can_eq(self.param_env, Ty::new_imm_ref(self.tcx,self.tcx.lifetimes.re_erased, found), expected) }); // FIXME: This could/should be extended to suggest `as_mut` and `as_deref_mut`, // but those checks need to be a bit more delicate and the benefit is diminishing. @@ -515,7 +515,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self.tcx.hir().is_inside_const_context(hir_id) || !expected.is_box() || found.is_box() { return false; } - if self.can_coerce(self.tcx.mk_box(found), expected) { + if self.can_coerce(Ty::new_box(self.tcx, found), expected) { let suggest_boxing = match found.kind() { ty::Tuple(tuple) if tuple.is_empty() => { SuggestBoxing::Unit { start: span.shrink_to_lo(), end: span } @@ -595,9 +595,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() { return false; } - let box_found = self.tcx.mk_box(found); - let pin_box_found = self.tcx.mk_lang_item(box_found, LangItem::Pin).unwrap(); - let pin_found = self.tcx.mk_lang_item(found, LangItem::Pin).unwrap(); + let box_found = Ty::new_box(self.tcx, found); + let pin_box_found = Ty::new_lang_item(self.tcx, box_found, LangItem::Pin).unwrap(); + let pin_found = Ty::new_lang_item(self.tcx, found, LangItem::Pin).unwrap(); match expected.kind() { ty::Adt(def, _) if Some(def.did()) == pin_did => { if self.can_coerce(pin_box_found, expected) { diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index fdbb153ec7d..86ea092bc40 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -312,7 +312,8 @@ pub fn resolve_interior<'a, 'tcx>( // Extract type components to build the witness type. let type_list = fcx.tcx.mk_type_list_from_iter(type_causes.iter().map(|cause| cause.ty)); let bound_vars = fcx.tcx.mk_bound_variable_kinds(&bound_vars); - let witness = fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars)); + let witness = + Ty::new_generator_witness(fcx.tcx, ty::Binder::bind_with_vars(type_list, bound_vars)); drop(typeck_results); // Store the generator types and spans into the typeck results for this generator. @@ -361,7 +362,8 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { let ty = self.interior_visitor.fcx.typeck_results.borrow().node_type(id); let tcx = self.interior_visitor.fcx.tcx; - let ty = tcx.mk_ref( + let ty = Ty::new_ref( + tcx, // Use `ReErased` as `resolve_interior` is going to replace all the // regions anyway. tcx.lifetimes.re_erased, diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 6f7288ed7e5..6f82ffcfe4a 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -154,7 +154,7 @@ fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tc fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { let fallback = move || { let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id)); - tcx.ty_error_with_message(span, "diagnostic only typeck table used") + Ty::new_error_with_message(tcx, span, "diagnostic only typeck table used") }; typeck_with_fallback(tcx, def_id, fallback) } diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index 6c8589493cb..a1aa090841a 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -277,9 +277,11 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { adjustment::Adjust::Deref(overloaded) => { // Equivalent to *expr or something similar. let base = if let Some(deref) = overloaded { - let ref_ty = self - .tcx() - .mk_ref(deref.region, ty::TypeAndMut { ty: target, mutbl: deref.mutbl }); + let ref_ty = Ty::new_ref( + self.tcx(), + deref.region, + ty::TypeAndMut { ty: target, mutbl: deref.mutbl }, + ); self.cat_rvalue(expr.hir_id, expr.span, ref_ty) } else { previous()? @@ -489,7 +491,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { let ty::Ref(region, _, mutbl) = *base_ty.kind() else { span_bug!(expr.span, "cat_overloaded_place: base is not a reference"); }; - let ref_ty = self.tcx().mk_ref(region, ty::TypeAndMut { ty: place_ty, mutbl }); + let ref_ty = Ty::new_ref(self.tcx(), region, ty::TypeAndMut { ty: place_ty, mutbl }); let base = self.cat_rvalue(expr.hir_id, expr.span, ref_ty); self.cat_deref(expr, base) diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 31894d25b60..55ad99e55af 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -143,7 +143,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // a custom error in that case. if illegal_sized_bound.is_none() { self.add_obligations( - self.tcx.mk_fn_ptr(method_sig), + Ty::new_fn_ptr(self.tcx, method_sig), all_substs, method_predicates, pick.item.def_id, @@ -171,7 +171,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // time writing the results into the various typeck results. let mut autoderef = self.autoderef(self.call_expr.span, unadjusted_self_ty); let Some((ty, n)) = autoderef.nth(pick.autoderefs) else { - return self.tcx.ty_error_with_message( + return Ty::new_error_with_message(self.tcx, rustc_span::DUMMY_SP, format!("failed autoderef {}", pick.autoderefs), ); @@ -179,7 +179,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { assert_eq!(n, pick.autoderefs); let mut adjustments = self.adjust_steps(&autoderef); - let mut target = self.structurally_resolved_type(autoderef.span(), ty); + let mut target = self.structurally_resolve_type(autoderef.span(), ty); match pick.autoref_or_ptr_adjustment { Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => { @@ -187,7 +187,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // Type we're wrapping in a reference, used later for unsizing let base_ty = target; - target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl, ty: target }); + target = Ty::new_ref(self.tcx, region, ty::TypeAndMut { mutbl, ty: target }); // Method call receivers are the primary use case // for two-phase borrows. @@ -200,16 +200,18 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { if unsize { let unsized_ty = if let ty::Array(elem_ty, _) = base_ty.kind() { - self.tcx.mk_slice(*elem_ty) + Ty::new_slice(self.tcx, *elem_ty) } else { bug!( "AutorefOrPtrAdjustment's unsize flag should only be set for array ty, found {}", base_ty ) }; - target = self - .tcx - .mk_ref(region, ty::TypeAndMut { mutbl: mutbl.into(), ty: unsized_ty }); + target = Ty::new_ref( + self.tcx, + region, + ty::TypeAndMut { mutbl: mutbl.into(), ty: unsized_ty }, + ); adjustments .push(Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target }); } @@ -218,7 +220,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { target = match target.kind() { &ty::RawPtr(ty::TypeAndMut { ty, mutbl }) => { assert!(mutbl.is_mut()); - self.tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty }) + Ty::new_ptr(self.tcx, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty }) } other => panic!("Cannot adjust receiver type {:?} to const ptr", other), }; diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index ebd7b3123eb..e52cea1889f 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -205,9 +205,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(span) = result.illegal_sized_bound { let mut needs_mut = false; if let ty::Ref(region, t_type, mutability) = self_ty.kind() { - let trait_type = self - .tcx - .mk_ref(*region, ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() }); + let trait_type = Ty::new_ref( + self.tcx, + *region, + ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() }, + ); // We probe again to see if there might be a borrow mutability discrepancy. match self.lookup_probe( segment.ident, @@ -464,7 +466,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); // Also add an obligation for the method type being well-formed. - let method_ty = tcx.mk_fn_ptr(ty::Binder::dummy(fn_sig)); + let method_ty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(fn_sig)); debug!( "lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}", method_ty, obligation diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 35d70968ce7..52e62837f35 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -451,7 +451,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { // Ended up encountering a type variable when doing autoderef, // but it may not be a type variable after processing obligations - // in our local `FnCtxt`, so don't call `structurally_resolved_type`. + // in our local `FnCtxt`, so don't call `structurally_resolve_type`. let ty = &bad_ty.ty; let ty = self .probe_instantiate_query_response(span, &orig_values, ty) @@ -465,7 +465,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Error(guar) => guar, _ => bug!("unexpected bad final type in method autoderef"), }; - self.demand_eqtype(span, ty, self.tcx.ty_error(guar)); + self.demand_eqtype(span, ty, Ty::new_error(self.tcx, guar)); return Err(MethodError::NoMatch(NoMatchData { static_candidates: Vec::new(), unsatisfied_predicates: Vec::new(), @@ -551,7 +551,7 @@ fn method_autoderef_steps<'tcx>( steps.push(CandidateStep { self_ty: infcx.make_query_response_ignoring_pending_obligations( inference_vars, - infcx.tcx.mk_slice(*elem_ty), + Ty::new_slice(infcx.tcx, *elem_ty), ), autoderefs: dereferences, // this could be from an unsafe deref if we had @@ -847,8 +847,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { | ty::ClauseKind::Projection(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) - | ty::ClauseKind::TypeWellFormedFromEnv(_) => None, + | ty::ClauseKind::ConstEvaluatable(_) => None, } }); @@ -1216,7 +1215,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // In general, during probing we erase regions. let region = tcx.lifetimes.re_erased; - let autoref_ty = tcx.mk_ref(region, ty::TypeAndMut { ty: self_ty, mutbl }); + let autoref_ty = Ty::new_ref(tcx, region, ty::TypeAndMut { ty: self_ty, mutbl }); self.pick_method(autoref_ty, unstable_candidates).map(|r| { r.map(|mut pick| { pick.autoderefs = step.autoderefs; @@ -1246,7 +1245,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }; let const_self_ty = ty::TypeAndMut { ty, mutbl: hir::Mutability::Not }; - let const_ptr_ty = self.tcx.mk_ptr(const_self_ty); + let const_ptr_ty = Ty::new_ptr(self.tcx, const_self_ty); self.pick_method(const_ptr_ty, unstable_candidates).map(|r| { r.map(|mut pick| { pick.autoderefs = step.autoderefs; diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 67fb7c1d48c..5f924f30936 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -211,7 +211,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind() { if needs_mut { - let trait_type = self.tcx.mk_ref( + let trait_type = Ty::new_ref( + self.tcx, *region, ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() }, ); @@ -647,7 +648,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let projection_ty = pred.skip_binder().projection_ty; let substs_with_infer_self = tcx.mk_substs_from_iter( - iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into()) + iter::once(Ty::new_var(tcx, ty::TyVid::from_u32(0)).into()) .chain(projection_ty.substs.iter().skip(1)), ); @@ -2408,8 +2409,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // just this list. for (rcvr_ty, post) in &[ (rcvr_ty, ""), - (self.tcx.mk_mut_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "), - (self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&"), + (Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "), + (Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty), "&"), ] { match self.lookup_probe_for_diagnostic( item_name, @@ -2444,10 +2445,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } for (rcvr_ty, pre) in &[ - (self.tcx.mk_lang_item(*rcvr_ty, LangItem::OwnedBox), "Box::new"), - (self.tcx.mk_lang_item(*rcvr_ty, LangItem::Pin), "Pin::new"), - (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Arc), "Arc::new"), - (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Rc), "Rc::new"), + (Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::OwnedBox), "Box::new"), + (Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::Pin), "Pin::new"), + (Ty::new_diagnostic_item(self.tcx, *rcvr_ty, sym::Arc), "Arc::new"), + (Ty::new_diagnostic_item(self.tcx, *rcvr_ty, sym::Rc), "Rc::new"), ] { if let Some(new_rcvr_t) = *rcvr_ty && let Ok(pick) = self.lookup_probe_for_diagnostic( diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 4f3d1d45679..1eae258c1b2 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -38,7 +38,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) { self.enforce_builtin_binop_types(lhs.span, lhs_ty, rhs.span, rhs_ty, op); - self.tcx.mk_unit() + Ty::new_unit(self.tcx) } else { return_ty }; @@ -297,7 +297,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // error types are considered "builtin" Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => { - self.tcx.ty_error_misc() + Ty::new_misc_error(self.tcx) } Err(errors) => { let (_, trait_def_id) = @@ -568,7 +568,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let reported = err.emit(); - self.tcx.ty_error(reported) + Ty::new_error(self.tcx, reported) } }; @@ -752,7 +752,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } err.emit() }); - self.tcx.ty_error(guar) + Ty::new_error(self.tcx, guar) } } } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 9c989d3b4b2..19f82fbd3bf 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -393,7 +393,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // They can denote both statically and dynamically-sized byte arrays. let mut pat_ty = ty; if let hir::ExprKind::Lit(Spanned { node: ast::LitKind::ByteStr(..), .. }) = lt.kind { - let expected = self.structurally_resolved_type(span, expected); + let expected = self.structurally_resolve_type(span, expected); if let ty::Ref(_, inner_ty, _) = expected.kind() && matches!(inner_ty.kind(), ty::Slice(_)) { @@ -403,7 +403,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .borrow_mut() .treat_byte_string_as_slice .insert(lt.hir_id.local_id); - pat_ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_slice(tcx.types.u8)); + pat_ty = Ty::new_imm_ref(tcx,tcx.lifetimes.re_static, Ty::new_slice(tcx,tcx.types.u8)); } } @@ -412,7 +412,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expected = self.resolve_vars_if_possible(expected); pat_ty = match expected.kind() { ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().string() => expected, - ty::Str => tcx.mk_static_str(), + ty::Str => Ty::new_static_str(tcx,), _ => pat_ty, }; } @@ -474,7 +474,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // There exists a side that didn't meet our criteria that the end-point // be of a numeric or char type, as checked in `calc_side` above. let guar = self.emit_err_pat_range(span, lhs, rhs); - return self.tcx.ty_error(guar); + return Ty::new_error(self.tcx, guar); } // Unify each side with `expected`. @@ -494,14 +494,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { demand_eqtype(&mut rhs, lhs); if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) { - return self.tcx.ty_error_misc(); + return Ty::new_misc_error(self.tcx); } // Find the unified type and check if it's of numeric or char type again. // This check is needed if both sides are inference variables. // We require types to be resolved here so that we emit inference failure // rather than "_ is not a char or numeric". - let ty = self.structurally_resolved_type(span, expected); + let ty = self.structurally_resolve_type(span, expected); if !(ty.is_numeric() || ty.is_char() || ty.references_error()) { if let Some((ref mut fail, _, _)) = lhs { *fail = true; @@ -510,7 +510,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { *fail = true; } let guar = self.emit_err_pat_range(span, lhs, rhs); - return self.tcx.ty_error(guar); + return Ty::new_error(self.tcx, guar); } ty } @@ -848,7 +848,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) { Ok(data) => data, Err(guar) => { - let err = self.tcx.ty_error(guar); + let err = Ty::new_error(self.tcx, guar); for field in fields { let ti = ti; self.check_pat(field.pat, err, def_bm, ti); @@ -864,7 +864,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, has_rest_pat, def_bm, ti) { pat_ty } else { - self.tcx.ty_error_misc() + Ty::new_misc_error(self.tcx) } } @@ -884,12 +884,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Res::Err => { let e = tcx.sess.delay_span_bug(qpath.span(), "`Res::Err` but no error emitted"); self.set_tainted_by_errors(e); - return tcx.ty_error(e); + return Ty::new_error(tcx, e); } Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => { let expected = "unit struct, unit variant or constant"; let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, "E0533", expected); - return tcx.ty_error(e); + return Ty::new_error(tcx, e); } Res::SelfCtor(..) | Res::Def( @@ -1032,7 +1032,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; let on_error = |e| { for pat in subpats { - self.check_pat(pat, tcx.ty_error(e), def_bm, ti); + self.check_pat(pat, Ty::new_error(tcx, e), def_bm, ti); } }; let report_unexpected_res = |res: Res| { @@ -1049,7 +1049,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let e = tcx.sess.delay_span_bug(pat.span, "`Res::Err` but no error emitted"); self.set_tainted_by_errors(e); on_error(e); - return tcx.ty_error(e); + return Ty::new_error(tcx, e); } // Type-check the path. @@ -1057,7 +1057,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id); if !pat_ty.is_fn() { let e = report_unexpected_res(res); - return tcx.ty_error(e); + return Ty::new_error(tcx, e); } let variant = match res { @@ -1065,11 +1065,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let e = tcx.sess.delay_span_bug(pat.span, "`Res::Err` but no error emitted"); self.set_tainted_by_errors(e); on_error(e); - return tcx.ty_error(e); + return Ty::new_error(tcx, e); } Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => { let e = report_unexpected_res(res); - return tcx.ty_error(e); + return Ty::new_error(tcx, e); } Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res), _ => bug!("unexpected pattern resolution: {:?}", res), @@ -1112,7 +1112,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let e = self.e0023(pat.span, res, qpath, subpats, &variant.fields.raw, expected, had_err); on_error(e); - return tcx.ty_error(e); + return Ty::new_error(tcx, e); } pat_ty } @@ -1289,7 +1289,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut expected_len = elements.len(); if ddpos.as_opt_usize().is_some() { // Require known type only when `..` is present. - if let ty::Tuple(tys) = self.structurally_resolved_type(span, expected).kind() { + if let ty::Tuple(tys) = self.structurally_resolve_type(span, expected).kind() { expected_len = tys.len(); } } @@ -1303,16 +1303,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) }); let element_tys = tcx.mk_type_list_from_iter(element_tys_iter); - let pat_ty = tcx.mk_tup(element_tys); + let pat_ty = Ty::new_tup(tcx, element_tys); if let Some(mut err) = self.demand_eqtype_pat_diag(span, expected, pat_ty, ti) { let reported = err.emit(); // Walk subpatterns with an expected type of `err` in this case to silence // further errors being emitted when using the bindings. #50333 - let element_tys_iter = (0..max_len).map(|_| tcx.ty_error(reported)); + let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported)); for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat(elem, tcx.ty_error(reported), def_bm, ti); + self.check_pat(elem, Ty::new_error(tcx, reported), def_bm, ti); } - tcx.mk_tup_from_iter(element_tys_iter) + Ty::new_tup_from_iter(tcx, element_tys_iter) } else { for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { self.check_pat(elem, element_tys[i], def_bm, ti); @@ -1357,7 +1357,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Occupied(occupied) => { no_field_errors = false; let guar = self.error_field_already_bound(span, field.ident, *occupied.get()); - tcx.ty_error(guar) + Ty::new_error(tcx, guar) } Vacant(vacant) => { vacant.insert(span); @@ -1371,7 +1371,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .unwrap_or_else(|| { inexistent_fields.push(field); no_field_errors = false; - tcx.ty_error_misc() + Ty::new_misc_error(tcx) }) } }; @@ -1951,12 +1951,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { kind: TypeVariableOriginKind::TypeInference, span: inner.span, }); - let box_ty = tcx.mk_box(inner_ty); + let box_ty = Ty::new_box(tcx, inner_ty); self.demand_eqtype_pat(span, expected, box_ty, ti); (box_ty, inner_ty) } Err(guar) => { - let err = tcx.ty_error(guar); + let err = Ty::new_error(tcx, guar); (err, err) } }; @@ -2007,7 +2007,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } Err(guar) => { - let err = tcx.ty_error(guar); + let err = Ty::new_error(tcx, guar); (err, err) } }; @@ -2019,7 +2019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn new_ref_ty(&self, span: Span, mutbl: hir::Mutability, ty: Ty<'tcx>) -> Ty<'tcx> { let region = self.next_region_var(infer::PatternRegion(span)); let mt = ty::TypeAndMut { ty, mutbl }; - self.tcx.mk_ref(region, mt) + Ty::new_ref(self.tcx, region, mt) } /// Type check a slice pattern. @@ -2042,7 +2042,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { def_bm: BindingMode, ti: TopInfo<'tcx>, ) -> Ty<'tcx> { - let expected = self.structurally_resolved_type(span, expected); + let expected = self.structurally_resolve_type(span, expected); let (element_ty, opt_slice_ty, inferred) = match *expected.kind() { // An array, so we might have something like `let [a, b, c] = [0, 1, 2];`. ty::Array(element_ty, len) => { @@ -2061,7 +2061,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .error_reported() .err() .unwrap_or_else(|| self.error_expected_array_or_slice(span, expected, ti)); - let err = self.tcx.ty_error(guar); + let err = Ty::new_error(self.tcx, guar); (err, Some(err), err) } }; @@ -2108,7 +2108,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else if let Some(pat_len) = len.checked_sub(min_len) { // The variable-length pattern was there, // so it has an array type with the remaining elements left as its size... - return (Some(self.tcx.mk_array(element_ty, pat_len)), arr_ty); + return (Some(Ty::new_array(self.tcx, element_ty, pat_len)), arr_ty); } else { // ...however, in this case, there were no remaining elements. // That is, the slice pattern requires more than the array type offers. @@ -2117,7 +2117,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else if slice.is_none() { // We have a pattern with a fixed length, // which we can use to infer the length of the array. - let updated_arr_ty = self.tcx.mk_array(element_ty, min_len); + let updated_arr_ty = Ty::new_array(self.tcx, element_ty, min_len); self.demand_eqtype(span, updated_arr_ty, arr_ty); return (None, updated_arr_ty); } else { @@ -2128,7 +2128,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // If we get here, we must have emitted an error. - (Some(self.tcx.ty_error(guar)), arr_ty) + (Some(Ty::new_error(self.tcx, guar)), arr_ty) } fn error_scrutinee_inconsistent_length( diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index e2b1dc007ba..826cee3f982 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -90,7 +90,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } let reported = err.emit(); - Some((self.tcx.ty_error(reported), self.tcx.ty_error(reported))) + Some((Ty::new_error(self.tcx, reported), Ty::new_error(self.tcx, reported))) } /// To type-check `base_expr[index_expr]`, we progressively autoderef @@ -107,7 +107,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { index_expr: &hir::Expr<'_>, ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { let adjusted_ty = - self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false)); + self.structurally_resolve_type(autoderef.span(), autoderef.final_ty(false)); debug!( "try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \ index_ty={:?})", @@ -138,7 +138,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if unsize { // We only unsize arrays here. if let ty::Array(element_ty, _) = adjusted_ty.kind() { - self_ty = self.tcx.mk_slice(*element_ty); + self_ty = Ty::new_slice(self.tcx, *element_ty); } else { continue; } @@ -162,7 +162,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind() { adjustments.push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(*region, AutoBorrowMutability::Not)), - target: self.tcx.mk_ref( + target: Ty::new_ref( + self.tcx, *region, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: adjusted_ty }, ), @@ -427,9 +428,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { allow_two_phase_borrow: AllowTwoPhase::No, }; adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)); - adjustment.target = self - .tcx - .mk_ref(*region, ty::TypeAndMut { ty: source, mutbl: mutbl.into() }); + adjustment.target = Ty::new_ref( + self.tcx, + *region, + ty::TypeAndMut { ty: source, mutbl: mutbl.into() }, + ); } source = adjustment.target; } diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 9458099f56f..208c40a3932 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -300,7 +300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Build a tuple (U0..Un) of the final upvar types U0..Un // and unify the upvar tuple type in the closure with it: - let final_tupled_upvars_type = self.tcx.mk_tup(&final_upvar_tys); + let final_tupled_upvars_type = Ty::new_tup(self.tcx, &final_upvar_tys); self.demand_suptype(span, substs.tupled_upvars_ty(), final_tupled_upvars_type); let fake_reads = delegate @@ -314,8 +314,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.typeck_results.borrow_mut().closure_size_eval.insert( closure_def_id, ClosureSizeProfileData { - before_feature_tys: self.tcx.mk_tup(&before_feature_tys), - after_feature_tys: self.tcx.mk_tup(&after_feature_tys), + before_feature_tys: Ty::new_tup(self.tcx, &before_feature_tys), + after_feature_tys: Ty::new_tup(self.tcx, &after_feature_tys), }, ); } @@ -1665,9 +1665,11 @@ fn apply_capture_kind_on_capture_ty<'tcx>( ) -> Ty<'tcx> { match capture_kind { ty::UpvarCapture::ByValue => ty, - ty::UpvarCapture::ByRef(kind) => { - tcx.mk_ref(region.unwrap(), ty::TypeAndMut { ty: ty, mutbl: kind.to_mutbl_lossy() }) - } + ty::UpvarCapture::ByRef(kind) => Ty::new_ref( + tcx, + region.unwrap(), + ty::TypeAndMut { ty: ty, mutbl: kind.to_mutbl_lossy() }, + ), } } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 0cf3a4e877a..01332483a06 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -232,7 +232,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // to access an nonexistent index. We assume that more relevant errors will // already have been emitted, so we only gate on this with an ICE if no // error has been emitted. (#64638) - self.fcx.tcx.ty_error_with_message( + Ty::new_error_with_message( + self.fcx.tcx, e.span, format!("bad index {:?} for base: `{:?}`", index, base), ) @@ -823,7 +824,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> { debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t); let e = self.report_error(t); self.replaced_with_error = Some(e); - self.fcx.tcx.ty_error(e) + Ty::new_error(self.fcx.tcx, e) } } } @@ -840,7 +841,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> { debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct); let e = self.report_error(ct); self.replaced_with_error = Some(e); - self.fcx.tcx.const_error(ct.ty(), e) + ty::Const::new_error(self.fcx.tcx, e, ct.ty()) } } } diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index f1a187d2677..433735e827b 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -40,6 +40,7 @@ pub enum DefineOpaqueTypes { No, } +#[derive(Clone, Copy)] pub struct At<'a, 'tcx> { pub infcx: &'a InferCtxt<'tcx>, pub cause: &'a ObligationCause<'tcx>, diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index bf53a73f398..e57532e2de2 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -382,7 +382,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { // any equated inference vars correctly! let root_vid = self.infcx.root_var(vid); if root_vid != vid { - t = self.infcx.tcx.mk_ty_var(root_vid); + t = Ty::new_var(self.infcx.tcx, root_vid); vid = root_vid; } @@ -497,7 +497,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { // any equated inference vars correctly! let root_vid = self.infcx.root_const_var(vid); if root_vid != vid { - ct = self.infcx.tcx.mk_const(ty::InferConst::Var(root_vid), ct.ty()); + ct = ty::Const::new_var(self.infcx.tcx, root_vid, ct.ty()); vid = root_vid; } @@ -785,7 +785,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { self.fold_ty(bound_to) } else { let var = self.canonical_var(info, ty_var.into()); - self.interner().mk_bound(self.binder_index, var.into()) + Ty::new_bound(self.tcx, self.binder_index, var.into()) } } @@ -804,10 +804,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { self.fold_const(bound_to) } else { let var = self.canonical_var(info, const_var.into()); - self.interner().mk_const( - ty::ConstKind::Bound(self.binder_index, var), - self.fold_ty(const_var.ty()), - ) + ty::Const::new_bound(self.tcx, self.binder_index, var, self.fold_ty(const_var.ty())) } } } diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index c8c318c3f02..f765c41a367 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -26,7 +26,7 @@ use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, TypeVari use rustc_index::IndexVec; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::GenericArg; -use rustc_middle::ty::{self, List, TyCtxt}; +use rustc_middle::ty::{self, List, Ty, TyCtxt}; use rustc_span::source_map::Span; pub use rustc_middle::infer::canonical::*; @@ -128,7 +128,7 @@ impl<'tcx> InferCtxt<'tcx> { CanonicalVarKind::PlaceholderTy(ty::PlaceholderType { universe, bound }) => { let universe_mapped = universe_map(universe); let placeholder_mapped = ty::PlaceholderType { universe: universe_mapped, bound }; - self.tcx.mk_placeholder(placeholder_mapped).into() + Ty::new_placeholder(self.tcx, placeholder_mapped).into() } CanonicalVarKind::Region(ui) => self @@ -155,7 +155,7 @@ impl<'tcx> InferCtxt<'tcx> { CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, bound }, ty) => { let universe_mapped = universe_map(universe); let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, bound }; - self.tcx.mk_const(placeholder_mapped, ty).into() + ty::Const::new_placeholder(self.tcx, placeholder_mapped, ty).into() } } } diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 32054e6d125..9c3ab04deae 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -520,7 +520,7 @@ impl<'tcx> InferCtxt<'tcx> { self.at(cause, param_env) .eq( DefineOpaqueTypes::Yes, - self.tcx.mk_opaque(a.def_id.to_def_id(), a.substs), + Ty::new_opaque(self.tcx, a.def_id.to_def_id(), a.substs), b, )? .obligations, diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index fc6ff01c00c..a9cdb8c51cf 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -189,11 +189,11 @@ impl<'tcx> InferCtxt<'tcx> { // HACK: equating both sides with `[const error]` eagerly prevents us // from leaving unconstrained inference vars during things like impl // matching in the solver. - let a_error = self.tcx.const_error(a.ty(), guar); + let a_error = ty::Const::new_error(self.tcx, guar, a.ty()); if let ty::ConstKind::Infer(InferConst::Var(vid)) = a.kind() { return self.unify_const_variable(vid, a_error, relation.param_env()); } - let b_error = self.tcx.const_error(b.ty(), guar); + let b_error = ty::Const::new_error(self.tcx, guar, b.ty()); if let ty::ConstKind::Infer(InferConst::Var(vid)) = b.kind() { return self.unify_const_variable(vid, b_error, relation.param_env()); } @@ -322,8 +322,8 @@ impl<'tcx> InferCtxt<'tcx> { .unify_var_value(vid, Some(val)) .map_err(|e| int_unification_error(vid_is_expected, e))?; match val { - IntType(v) => Ok(self.tcx.mk_mach_int(v)), - UintType(v) => Ok(self.tcx.mk_mach_uint(v)), + IntType(v) => Ok(Ty::new_int(self.tcx, v)), + UintType(v) => Ok(Ty::new_uint(self.tcx, v)), } } @@ -338,7 +338,7 @@ impl<'tcx> InferCtxt<'tcx> { .float_unification_table() .unify_var_value(vid, Some(ty::FloatVarValue(val))) .map_err(|e| float_unification_error(vid_is_expected, e))?; - Ok(self.tcx.mk_mach_float(val)) + Ok(Ty::new_float(self.tcx, val)) } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 15213c4b023..b826ced0453 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -315,7 +315,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let mut err = tcx.sess.create_err(errors::OpaqueCapturesLifetime { span, - opaque_ty: tcx.mk_opaque(opaque_ty_key.def_id.to_def_id(), opaque_ty_key.substs), + opaque_ty: Ty::new_opaque(tcx, opaque_ty_key.def_id.to_def_id(), opaque_ty_key.substs), opaque_ty_span: tcx.def_span(opaque_ty_key.def_id), }); diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index f3b2ec4c5e3..bb75ecc6adb 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -265,9 +265,9 @@ impl<'tcx> InferCtxt<'tcx> { kind: UnderspecifiedArgKind::Type { prefix: "type parameter".into(), }, - parent: def_id.and_then(|def_id| { - InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id) - }), + parent: InferenceDiagnosticsParentData::for_def_id( + self.tcx, def_id, + ), }; } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index aad9885827d..a9b485a6f7e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -288,7 +288,7 @@ pub fn suggest_new_region_bound( // Get the identity type for this RPIT let did = item_id.owner_id.to_def_id(); - let ty = tcx.mk_opaque(did, ty::InternalSubsts::identity_for_item(tcx, did)); + let ty = Ty::new_opaque(tcx, did, ty::InternalSubsts::identity_for_item(tcx, did)); if let Some(span) = opaque.bounds.iter().find_map(|arg| match arg { GenericBound::Outlives(Lifetime { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index ce70bcc5c85..12d38ced030 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -41,8 +41,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // all of the region highlighting machinery only deals with those. let guar = self.emit_err( var_origin.span(), - self.cx.tcx.mk_fn_ptr(ty::Binder::dummy(expected)), - self.cx.tcx.mk_fn_ptr(ty::Binder::dummy(found)), + Ty::new_fn_ptr(self.cx.tcx,ty::Binder::dummy(expected)), + Ty::new_fn_ptr(self.cx.tcx,ty::Binder::dummy(found)), *trait_item_def_id, ); return Some(guar); diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 07a9eff2dbe..e55e9e75fb6 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -11,7 +11,7 @@ use rustc_errors::{ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::{self, IsSuggestable, Region}; +use rustc_middle::ty::{self, IsSuggestable, Region, Ty}; use rustc_span::symbol::kw; use super::ObligationCauseAsDiagArg; @@ -304,7 +304,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let trait_substs = trait_ref .subst_identity() // Replace the explicit self type with `Self` for better suggestion rendering - .with_self_ty(self.tcx, self.tcx.mk_ty_param(0, kw::SelfUpper)) + .with_self_ty(self.tcx, Ty::new_param(self.tcx, 0, kw::SelfUpper)) .substs; let trait_item_substs = ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id) .rebase_onto(self.tcx, impl_def_id, trait_substs); diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index 7293de4c6c5..c9a8f8131df 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -574,7 +574,9 @@ fn foo(&self) -> Self::T { String::new() } let Some(hir_id) = body_owner_def_id.as_local() else { return false; }; - let hir_id = tcx.hir().local_def_id_to_hir_id(hir_id); + let Some(hir_id) = tcx.opt_local_def_id_to_hir_id(hir_id) else { + return false; + }; // When `body_owner` is an `impl` or `trait` item, look in its associated types for // `expected` and point at it. let parent_id = tcx.hir().get_parent_item(hir_id); diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index 0219167f6e5..05769b7907a 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -95,7 +95,7 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { Entry::Vacant(entry) => { let index = self.const_freshen_count; self.const_freshen_count += 1; - let ct = self.infcx.tcx.mk_const(freshener(index), ty); + let ct = ty::Const::new_infer(self.infcx.tcx, freshener(index), ty); entry.insert(ct); ct } @@ -188,7 +188,7 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { match v { ty::TyVar(v) => { let opt_ty = self.infcx.inner.borrow_mut().type_variables().probe(v).known(); - Some(self.freshen_ty(opt_ty, ty::TyVar(v), |n| self.infcx.tcx.mk_fresh_ty(n))) + Some(self.freshen_ty(opt_ty, ty::TyVar(v), |n| Ty::new_fresh(self.infcx.tcx, n))) } ty::IntVar(v) => Some( @@ -200,7 +200,7 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { .probe_value(v) .map(|v| v.to_type(self.infcx.tcx)), ty::IntVar(v), - |n| self.infcx.tcx.mk_fresh_int_ty(n), + |n| Ty::new_fresh_int(self.infcx.tcx, n), ), ), @@ -213,7 +213,7 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { .probe_value(v) .map(|v| v.to_type(self.infcx.tcx)), ty::FloatVar(v), - |n| self.infcx.tcx.mk_fresh_float_ty(n), + |n| Ty::new_fresh_float(self.infcx.tcx, n), ), ), diff --git a/compiler/rustc_infer/src/infer/generalize.rs b/compiler/rustc_infer/src/infer/generalize.rs index d4a1dacde10..78025016757 100644 --- a/compiler/rustc_infer/src/infer/generalize.rs +++ b/compiler/rustc_infer/src/infer/generalize.rs @@ -277,7 +277,7 @@ where let origin = *inner.type_variables().var_origin(vid); let new_var_id = inner.type_variables().new_var(self.for_universe, origin); - let u = self.tcx().mk_ty_var(new_var_id); + let u = Ty::new_var(self.tcx(), new_var_id); // Record that we replaced `vid` with `new_var_id` as part of a generalization // operation. This is needed to detect cyclic types. To see why, see the @@ -398,7 +398,7 @@ where origin: var_value.origin, val: ConstVariableValue::Unknown { universe: self.for_universe }, }); - Ok(self.tcx().mk_const(new_var_id, c.ty())) + Ok(ty::Const::new_var(self.tcx(), new_var_id, c.ty())) } } } @@ -412,7 +412,11 @@ where substs, substs, )?; - Ok(self.tcx().mk_const(ty::UnevaluatedConst { def, substs }, c.ty())) + Ok(ty::Const::new_unevaluated( + self.tcx(), + ty::UnevaluatedConst { def, substs }, + c.ty(), + )) } ty::ConstKind::Placeholder(placeholder) => { if self.for_universe.can_name(placeholder.universe) { diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index 974bc2f1153..510b1797d3c 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -6,7 +6,7 @@ use super::{HigherRankedType, InferCtxt}; use crate::infer::CombinedSnapshot; use rustc_middle::ty::fold::FnMutDelegate; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; -use rustc_middle::ty::{self, Binder, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, Binder, Ty, TyCtxt, TypeFoldable}; impl<'a, 'tcx> CombineFields<'a, 'tcx> { /// Checks whether `for<..> sub <: for<..> sup` holds. @@ -88,13 +88,14 @@ impl<'tcx> InferCtxt<'tcx> { ) }, types: &mut |bound_ty: ty::BoundTy| { - self.tcx.mk_placeholder(ty::PlaceholderType { - universe: next_universe, - bound: bound_ty, - }) + Ty::new_placeholder( + self.tcx, + ty::PlaceholderType { universe: next_universe, bound: bound_ty }, + ) }, consts: &mut |bound_var: ty::BoundVar, ty| { - self.tcx.mk_const( + ty::Const::new_placeholder( + self.tcx, ty::PlaceholderConst { universe: next_universe, bound: bound_var }, ty, ) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index f1f5ac81fb7..fca32b73d1d 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -725,19 +725,19 @@ impl<'tcx> InferCtxt<'tcx> { .type_variables() .unsolved_variables() .into_iter() - .map(|t| self.tcx.mk_ty_var(t)) + .map(|t| Ty::new_var(self.tcx, t)) .collect(); vars.extend( (0..inner.int_unification_table().len()) .map(|i| ty::IntVid { index: i as u32 }) .filter(|&vid| inner.int_unification_table().probe_value(vid).is_none()) - .map(|v| self.tcx.mk_int_var(v)), + .map(|v| Ty::new_int_var(self.tcx, v)), ); vars.extend( (0..inner.float_unification_table().len()) .map(|i| ty::FloatVid { index: i as u32 }) .filter(|&vid| inner.float_unification_table().probe_value(vid).is_none()) - .map(|v| self.tcx.mk_float_var(v)), + .map(|v| Ty::new_float_var(self.tcx, v)), ); vars } @@ -978,7 +978,7 @@ impl<'tcx> InferCtxt<'tcx> { } pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - self.tcx.mk_ty_var(self.next_ty_var_id(origin)) + Ty::new_var(self.tcx, self.next_ty_var_id(origin)) } pub fn next_ty_var_id_in_universe( @@ -995,11 +995,11 @@ impl<'tcx> InferCtxt<'tcx> { universe: ty::UniverseIndex, ) -> Ty<'tcx> { let vid = self.next_ty_var_id_in_universe(origin, universe); - self.tcx.mk_ty_var(vid) + Ty::new_var(self.tcx, vid) } pub fn next_const_var(&self, ty: Ty<'tcx>, origin: ConstVariableOrigin) -> ty::Const<'tcx> { - self.tcx.mk_const(self.next_const_var_id(origin), ty) + ty::Const::new_var(self.tcx, self.next_const_var_id(origin), ty) } pub fn next_const_var_in_universe( @@ -1013,7 +1013,7 @@ impl<'tcx> InferCtxt<'tcx> { .borrow_mut() .const_unification_table() .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } }); - self.tcx.mk_const(vid, ty) + ty::Const::new_var(self.tcx, vid, ty) } pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid<'tcx> { @@ -1028,7 +1028,7 @@ impl<'tcx> InferCtxt<'tcx> { } pub fn next_int_var(&self) -> Ty<'tcx> { - self.tcx.mk_int_var(self.next_int_var_id()) + Ty::new_int_var(self.tcx, self.next_int_var_id()) } fn next_float_var_id(&self) -> FloatVid { @@ -1036,7 +1036,7 @@ impl<'tcx> InferCtxt<'tcx> { } pub fn next_float_var(&self) -> Ty<'tcx> { - self.tcx.mk_float_var(self.next_float_var_id()) + Ty::new_float_var(self.tcx, self.next_float_var_id()) } /// Creates a fresh region variable with the next available index. @@ -1110,13 +1110,13 @@ impl<'tcx> InferCtxt<'tcx> { TypeVariableOrigin { kind: TypeVariableOriginKind::TypeParameterDefinition( param.name, - Some(param.def_id), + param.def_id, ), span, }, ); - self.tcx.mk_ty_var(ty_var_id).into() + Ty::new_var(self.tcx, ty_var_id).into() } GenericParamDefKind::Const { .. } => { let origin = ConstVariableOrigin { @@ -1131,15 +1131,15 @@ impl<'tcx> InferCtxt<'tcx> { origin, val: ConstVariableValue::Unknown { universe: self.universe() }, }); - self.tcx - .mk_const( - const_var_id, - self.tcx - .type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), - ) - .into() + ty::Const::new_var( + self.tcx, + const_var_id, + self.tcx + .type_of(param.def_id) + .no_bound_vars() + .expect("const parameter types cannot be generic"), + ) + .into() } } } @@ -1265,7 +1265,7 @@ impl<'tcx> InferCtxt<'tcx> { if let Some(value) = inner.int_unification_table().probe_value(vid) { value.to_type(self.tcx) } else { - self.tcx.mk_int_var(inner.int_unification_table().find(vid)) + Ty::new_int_var(self.tcx, inner.int_unification_table().find(vid)) } } @@ -1276,7 +1276,7 @@ impl<'tcx> InferCtxt<'tcx> { if let Some(value) = inner.float_unification_table().probe_value(vid) { value.to_type(self.tcx) } else { - self.tcx.mk_float_var(inner.float_unification_table().find(vid)) + Ty::new_float_var(self.tcx, inner.float_unification_table().find(vid)) } } @@ -1472,7 +1472,7 @@ impl<'tcx> InferCtxt<'tcx> { span: Option<Span>, ) -> Result<ty::Const<'tcx>, ErrorHandled> { match self.const_eval_resolve(param_env, unevaluated, span) { - Ok(Some(val)) => Ok(self.tcx.mk_const(val, ty)), + Ok(Some(val)) => Ok(ty::Const::new_value(self.tcx, val, ty)), Ok(None) => { let tcx = self.tcx; let def_id = unevaluated.def; @@ -1945,13 +1945,16 @@ fn replace_param_and_infer_substs_with_placeholder<'tcx>( self.idx += 1; idx }; - self.tcx.mk_placeholder(ty::PlaceholderType { - universe: ty::UniverseIndex::ROOT, - bound: ty::BoundTy { - var: ty::BoundVar::from_u32(idx), - kind: ty::BoundTyKind::Anon, + Ty::new_placeholder( + self.tcx, + ty::PlaceholderType { + universe: ty::UniverseIndex::ROOT, + bound: ty::BoundTy { + var: ty::BoundVar::from_u32(idx), + kind: ty::BoundTyKind::Anon, + }, }, - }) + ) } else { t.super_fold_with(self) } @@ -1964,7 +1967,8 @@ fn replace_param_and_infer_substs_with_placeholder<'tcx>( if ty.has_non_region_param() || ty.has_non_region_infer() { bug!("const `{c}`'s type should not reference params or types"); } - self.tcx.mk_const( + ty::Const::new_placeholder( + self.tcx, ty::PlaceholderConst { universe: ty::UniverseIndex::ROOT, bound: ty::BoundVar::from_u32({ diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index c998c923760..cb92fc6ddb6 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -31,8 +31,7 @@ pub fn explicit_outlives_bounds<'tcx>( | ty::ClauseKind::Projection(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) - | ty::ClauseKind::TypeWellFormedFromEnv(_) => None, + | ty::ClauseKind::ConstEvaluatable(_) => None, }) } diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs index 75455533181..38e74e53868 100644 --- a/compiler/rustc_infer/src/infer/projection.rs +++ b/compiler/rustc_infer/src/infer/projection.rs @@ -21,29 +21,18 @@ impl<'tcx> InferCtxt<'tcx> { recursion_depth: usize, obligations: &mut Vec<PredicateObligation<'tcx>>, ) -> Ty<'tcx> { - if self.next_trait_solver() { - // FIXME(-Ztrait-solver=next): Instead of branching here, - // completely change the normalization routine with the new solver. - // - // The new solver correctly handles projection equality so this hack - // is not necessary. if re-enabled it should emit `PredicateKind::AliasRelate` - // not `PredicateKind::Clause(ClauseKind::Projection(..))` as in the new solver - // `Projection` is used as `normalizes-to` which will fail for `<T as Trait>::Assoc eq ?0`. - return projection_ty.to_ty(self.tcx); - } else { - let def_id = projection_ty.def_id; - let ty_var = self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::NormalizeProjectionType, - span: self.tcx.def_span(def_id), - }); - let projection = - ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Projection( - ty::ProjectionPredicate { projection_ty, term: ty_var.into() }, - ))); - let obligation = - Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection); - obligations.push(obligation); - ty_var - } + debug_assert!(!self.next_trait_solver()); + let def_id = projection_ty.def_id; + let ty_var = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::NormalizeProjectionType, + span: self.tcx.def_span(def_id), + }); + let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Projection( + ty::ProjectionPredicate { projection_ty, term: ty_var.into() }, + ))); + let obligation = + Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection); + obligations.push(obligation); + ty_var } } diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index d9f9d2aabdb..27e1ed56f31 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -118,7 +118,7 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { (&ty::Error(e), _) | (_, &ty::Error(e)) => { infcx.set_tainted_by_errors(e); - Ok(self.tcx().ty_error(e)) + Ok(Ty::new_error(self.tcx(), e)) } ( diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 9f85f9207e8..01c11d16345 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -123,7 +123,7 @@ pub enum TypeVariableOriginKind { NormalizeProjectionType, TypeInference, OpaqueTypeInference(DefId), - TypeParameterDefinition(Symbol, Option<DefId>), + TypeParameterDefinition(Symbol, DefId), /// One of the upvars or closure kind parameters in a `ClosureSubsts` /// (before it has been determined). diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index b5a7d0326a8..9f440f39849 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -25,9 +25,11 @@ impl<'tcx> InferCtxt<'tcx> { "impl has stricter requirements than trait" ); - if let Some(span) = self.tcx.hir().span_if_local(trait_item_def_id) { - let item_name = self.tcx.item_name(impl_item_def_id.to_def_id()); - err.span_label(span, format!("definition of `{}` from trait", item_name)); + if !self.tcx.is_impl_trait_in_trait(trait_item_def_id) { + if let Some(span) = self.tcx.hir().span_if_local(trait_item_def_id) { + let item_name = self.tcx.item_name(impl_item_def_id.to_def_id()); + err.span_label(span, format!("definition of `{}` from trait", item_name)); + } } err.span_label(error_span, format!("impl has extra requirement {}", requirement)); diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 66389cf5995..074ff7ec97f 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -3,7 +3,7 @@ use smallvec::smallvec; use crate::infer::outlives::components::{push_outlives_components, Component}; use crate::traits::{self, Obligation, PredicateObligation}; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; -use rustc_middle::ty::{self, ToPredicate, TyCtxt}; +use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -344,7 +344,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { } Component::Param(p) => { - let ty = tcx.mk_ty_param(p.index, p.name); + let ty = Ty::new_param(tcx, p.index, p.name); Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, r_min))) } @@ -370,9 +370,6 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { }), ); } - ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => { - // Nothing to elaborate - } ty::PredicateKind::Ambiguous => {} ty::PredicateKind::AliasRelate(..) => { // No diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 0f5dba1df14..09141afd137 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -841,7 +841,7 @@ fn test_unstable_options_tracking_hash() { tracked!(thir_unsafeck, true); tracked!(tiny_const_eval_limit, true); tracked!(tls_model, Some(TlsModel::GeneralDynamic)); - tracked!(trait_solver, TraitSolver::Chalk); + tracked!(trait_solver, TraitSolver::NextCoherence); tracked!(translate_remapped_path_to_local_path, false); tracked!(trap_unreachable, Some(false)); tracked!(treat_err_as_bug, NonZeroUsize::new(1)); diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index d511d2b1280..29335a8c0f4 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -367,13 +367,6 @@ impl Cursor<'_> { Some(|terminated| Byte { terminated }), ), - // c-string literal, raw c-string literal or identifier. - 'c' => self.c_or_byte_string( - |terminated| CStr { terminated }, - |n_hashes| RawCStr { n_hashes }, - None, - ), - // Identifier (this should be checked after other variant that can // start as identifier). c if is_id_start(c) => self.ident_or_unknown_prefix(), diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 3a177038ca8..b821933e908 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -674,21 +674,21 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { return; } let def = cx.tcx.adt_def(item.owner_id); - (def, cx.tcx.mk_adt(def, ty::List::empty())) + (def, Ty::new_adt(cx.tcx, def, ty::List::empty())) } hir::ItemKind::Union(_, ref ast_generics) => { if !ast_generics.params.is_empty() { return; } let def = cx.tcx.adt_def(item.owner_id); - (def, cx.tcx.mk_adt(def, ty::List::empty())) + (def, Ty::new_adt(cx.tcx, def, ty::List::empty())) } hir::ItemKind::Enum(_, ref ast_generics) => { if !ast_generics.params.is_empty() { return; } let def = cx.tcx.adt_def(item.owner_id); - (def, cx.tcx.mk_adt(def, ty::List::empty())) + (def, Ty::new_adt(cx.tcx, def, ty::List::empty())) } _ => return, }; @@ -1606,8 +1606,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { // Ignore bounds that a user can't type | ClauseKind::WellFormed(..) // FIXME(generic_const_exprs): `ConstEvaluatable` can be written - | ClauseKind::ConstEvaluatable(..) - | ClauseKind::TypeWellFormedFromEnv(_) => continue, + | ClauseKind::ConstEvaluatable(..) => continue, }; if predicate.is_global() { cx.emit_spanned_lint( diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 13164b0b339..3761754f3ae 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -1345,7 +1345,7 @@ impl<'tcx> LateContext<'tcx> { tcx.associated_items(trait_id) .find_by_name_and_kind(tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id) .and_then(|assoc| { - let proj = tcx.mk_projection(assoc.def_id, [self_ty]); + let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]); tcx.try_normalize_erasing_regions(self.param_env, proj).ok() }) } diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 79253cbc8b4..145de494835 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -533,6 +533,10 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { fn check_generic_param(&mut self, cx: &LateContext<'_>, param: &hir::GenericParam<'_>) { if let GenericParamKind::Const { .. } = param.kind { + // `rustc_host` params are explicitly allowed to be lowercase. + if cx.tcx.has_attr(param.def_id, sym::rustc_host) { + return; + } NonUpperCaseGlobals::check_upper_case(cx, "const parameter", ¶m.name.ident()); } } diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 63a56806a45..09a1651c2f5 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -97,7 +97,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { } let proj_ty = - cx.tcx.mk_projection(proj.projection_ty.def_id, proj.projection_ty.substs); + Ty::new_projection(cx.tcx, proj.projection_ty.def_id, proj.projection_ty.substs); // For every instance of the projection type in the bounds, // replace them with the term we're assigning to the associated // type in our opaque type. @@ -144,7 +144,8 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { OPAQUE_HIDDEN_INFERRED_BOUND, pred_span, OpaqueHiddenInferredBoundLint { - ty: cx.tcx.mk_opaque( + ty: Ty::new_opaque( + cx.tcx, def_id, ty::InternalSubsts::identity_for_item(cx.tcx, def_id), ), diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 9a2d45ccd66..2509d493a4c 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -862,12 +862,12 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t }; return get_nullable_type(cx, inner_field_ty); } - ty::Int(ty) => tcx.mk_mach_int(ty), - ty::Uint(ty) => tcx.mk_mach_uint(ty), - ty::RawPtr(ty_mut) => tcx.mk_ptr(ty_mut), + ty::Int(ty) => Ty::new_int(tcx, ty), + ty::Uint(ty) => Ty::new_uint(tcx, ty), + ty::RawPtr(ty_mut) => Ty::new_ptr(tcx, ty_mut), // As these types are always non-null, the nullable equivalent of // Option<T> of these types are their raw pointer counterparts. - ty::Ref(_region, ty, mutbl) => tcx.mk_ptr(ty::TypeAndMut { ty, mutbl }), + ty::Ref(_region, ty, mutbl) => Ty::new_ptr(tcx, ty::TypeAndMut { ty, mutbl }), ty::FnPtr(..) => { // There is no nullable equivalent for Rust's function pointers -- you // must use an Option<fn(..) -> _> to represent it. @@ -1379,7 +1379,29 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } - fn check_foreign_fn(&mut self, def_id: LocalDefId, decl: &hir::FnDecl<'_>) { + /// Check if a function's argument types and result type are "ffi-safe". + /// + /// For a external ABI function, argument types and the result type are walked to find fn-ptr + /// types that have external ABIs, as these still need checked. + fn check_fn(&mut self, def_id: LocalDefId, decl: &'tcx hir::FnDecl<'_>) { + let sig = self.cx.tcx.fn_sig(def_id).subst_identity(); + let sig = self.cx.tcx.erase_late_bound_regions(sig); + + for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) { + for (fn_ptr_ty, span) in self.find_fn_ptr_ty_with_external_abi(input_hir, *input_ty) { + self.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, false, false); + } + } + + if let hir::FnRetTy::Return(ref ret_hir) = decl.output { + for (fn_ptr_ty, span) in self.find_fn_ptr_ty_with_external_abi(ret_hir, sig.output()) { + self.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, false, true); + } + } + } + + /// Check if a function's argument types and result type are "ffi-safe". + fn check_foreign_fn(&mut self, def_id: LocalDefId, decl: &'tcx hir::FnDecl<'_>) { let sig = self.cx.tcx.fn_sig(def_id).subst_identity(); let sig = self.cx.tcx.erase_late_bound_regions(sig); @@ -1388,8 +1410,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } if let hir::FnRetTy::Return(ref ret_hir) = decl.output { - let ret_ty = sig.output(); - self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty, false, true); + self.check_type_for_ffi_and_report_errors(ret_hir.span, sig.output(), false, true); } } @@ -1404,28 +1425,131 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { SpecAbi::Rust | SpecAbi::RustCall | SpecAbi::RustIntrinsic | SpecAbi::PlatformIntrinsic ) } + + /// Find any fn-ptr types with external ABIs in `ty`. + /// + /// For example, `Option<extern "C" fn()>` returns `extern "C" fn()` + fn find_fn_ptr_ty_with_external_abi( + &self, + hir_ty: &hir::Ty<'tcx>, + ty: Ty<'tcx>, + ) -> Vec<(Ty<'tcx>, Span)> { + struct FnPtrFinder<'parent, 'a, 'tcx> { + visitor: &'parent ImproperCTypesVisitor<'a, 'tcx>, + spans: Vec<Span>, + tys: Vec<Ty<'tcx>>, + } + + impl<'parent, 'a, 'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'parent, 'a, 'tcx> { + fn visit_ty(&mut self, ty: &'_ hir::Ty<'_>) { + debug!(?ty); + if let hir::TyKind::BareFn(hir::BareFnTy { abi, .. }) = ty.kind + && !self.visitor.is_internal_abi(*abi) + { + self.spans.push(ty.span); + } + + hir::intravisit::walk_ty(self, ty) + } + } + + impl<'vis, 'a, 'tcx> ty::visit::TypeVisitor<TyCtxt<'tcx>> for FnPtrFinder<'vis, 'a, 'tcx> { + type BreakTy = Ty<'tcx>; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + if let ty::FnPtr(sig) = ty.kind() && !self.visitor.is_internal_abi(sig.abi()) { + self.tys.push(ty); + } + + ty.super_visit_with(self) + } + } + + let mut visitor = FnPtrFinder { visitor: &*self, spans: Vec::new(), tys: Vec::new() }; + ty.visit_with(&mut visitor); + hir::intravisit::Visitor::visit_ty(&mut visitor, hir_ty); + + iter::zip(visitor.tys.drain(..), visitor.spans.drain(..)).collect() + } } impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations { - fn check_foreign_item(&mut self, cx: &LateContext<'_>, it: &hir::ForeignItem<'_>) { + fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, it: &hir::ForeignItem<'tcx>) { let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Declaration }; let abi = cx.tcx.hir().get_foreign_abi(it.hir_id()); - if !vis.is_internal_abi(abi) { - match it.kind { - hir::ForeignItemKind::Fn(ref decl, _, _) => { - vis.check_foreign_fn(it.owner_id.def_id, decl); - } - hir::ForeignItemKind::Static(ref ty, _) => { - vis.check_foreign_static(it.owner_id, ty.span); - } - hir::ForeignItemKind::Type => (), + match it.kind { + hir::ForeignItemKind::Fn(ref decl, _, _) if !vis.is_internal_abi(abi) => { + vis.check_foreign_fn(it.owner_id.def_id, decl); + } + hir::ForeignItemKind::Static(ref ty, _) if !vis.is_internal_abi(abi) => { + vis.check_foreign_static(it.owner_id, ty.span); } + hir::ForeignItemKind::Fn(ref decl, _, _) => vis.check_fn(it.owner_id.def_id, decl), + hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => (), + } + } +} + +impl ImproperCTypesDefinitions { + fn check_ty_maybe_containing_foreign_fnptr<'tcx>( + &mut self, + cx: &LateContext<'tcx>, + hir_ty: &'tcx hir::Ty<'_>, + ty: Ty<'tcx>, + ) { + let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Definition }; + for (fn_ptr_ty, span) in vis.find_fn_ptr_ty_with_external_abi(hir_ty, ty) { + vis.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, true, false); } } } +/// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in +/// `extern "C" { }` blocks): +/// +/// - `extern "<abi>" fn` definitions are checked in the same way as the +/// `ImproperCtypesDeclarations` visitor checks functions if `<abi>` is external (e.g. "C"). +/// - All other items which contain types (e.g. other functions, struct definitions, etc) are +/// checked for extern fn-ptrs with external ABIs. impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { + match item.kind { + hir::ItemKind::Static(ty, ..) + | hir::ItemKind::Const(ty, ..) + | hir::ItemKind::TyAlias(ty, ..) => { + self.check_ty_maybe_containing_foreign_fnptr( + cx, + ty, + cx.tcx.type_of(item.owner_id).subst_identity(), + ); + } + // See `check_fn`.. + hir::ItemKind::Fn(..) => {} + // See `check_field_def`.. + hir::ItemKind::Union(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) => {} + // Doesn't define something that can contain a external type to be checked. + hir::ItemKind::Impl(..) + | hir::ItemKind::TraitAlias(..) + | hir::ItemKind::Trait(..) + | hir::ItemKind::OpaqueTy(..) + | hir::ItemKind::GlobalAsm(..) + | hir::ItemKind::ForeignMod { .. } + | hir::ItemKind::Mod(..) + | hir::ItemKind::Macro(..) + | hir::ItemKind::Use(..) + | hir::ItemKind::ExternCrate(..) => {} + } + } + + fn check_field_def(&mut self, cx: &LateContext<'tcx>, field: &'tcx hir::FieldDef<'tcx>) { + self.check_ty_maybe_containing_foreign_fnptr( + cx, + field.ty, + cx.tcx.type_of(field.def_id).subst_identity(), + ); + } + fn check_fn( &mut self, cx: &LateContext<'tcx>, @@ -1444,7 +1568,9 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions { }; let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Definition }; - if !vis.is_internal_abi(abi) { + if vis.is_internal_abi(abi) { + vis.check_fn(id, decl); + } else { vis.check_foreign_fn(id, decl); } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index ef82a6c17ee..87c542dc2e2 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3409,6 +3409,7 @@ declare_lint_pass! { UNSTABLE_SYNTAX_PRE_EXPANSION, UNSUPPORTED_CALLING_CONVENTIONS, UNUSED_ASSIGNMENTS, + UNUSED_ASSOCIATED_TYPE_BOUNDS, UNUSED_ATTRIBUTES, UNUSED_CRATE_DEPENDENCIES, UNUSED_EXTERN_CRATES, @@ -3469,6 +3470,32 @@ declare_lint! { } declare_lint! { + /// The `unused_associated_type_bounds` lint is emitted when an + /// associated type bound is added to a trait object, but the associated + /// type has a `where Self: Sized` bound, and is thus unavailable on the + /// trait object anyway. + /// + /// ### Example + /// + /// ```rust + /// trait Foo { + /// type Bar where Self: Sized; + /// } + /// type Mop = dyn Foo<Bar = ()>; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Just like methods with `Self: Sized` bounds are unavailable on trait + /// objects, associated types can be removed from the trait object. + pub UNUSED_ASSOCIATED_TYPE_BOUNDS, + Warn, + "detects unused `Foo = Bar` bounds in `dyn Trait<Foo = Bar>`" +} + +declare_lint! { /// The `unused_doc_comments` lint detects doc comments that aren't used /// by `rustdoc`. /// diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 553fe6cf087..bb7510b3a53 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -121,6 +121,32 @@ extern "C" LLVMValueRef LLVMRustGetNamedValue(LLVMModuleRef M, const char *Name, return wrap(unwrap(M)->getNamedValue(StringRef(Name, NameLen))); } +enum class LLVMRustTailCallKind { + None, + Tail, + MustTail, + NoTail, +}; + +static CallInst::TailCallKind fromRust(LLVMRustTailCallKind Kind) { + switch (Kind) { + case LLVMRustTailCallKind::None: + return CallInst::TailCallKind::TCK_None; + case LLVMRustTailCallKind::Tail: + return CallInst::TailCallKind::TCK_Tail; + case LLVMRustTailCallKind::MustTail: + return CallInst::TailCallKind::TCK_MustTail; + case LLVMRustTailCallKind::NoTail: + return CallInst::TailCallKind::TCK_NoTail; + default: + report_fatal_error("bad CallInst::TailCallKind."); + } +} + +extern "C" void LLVMRustSetTailCallKind(LLVMValueRef Call, LLVMRustTailCallKind TCK) { + unwrap<CallInst>(Call)->setTailCallKind(fromRust(TCK)); +} + extern "C" LLVMValueRef LLVMRustGetOrInsertFunction(LLVMModuleRef M, const char *Name, size_t NameLen, diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index cc58d51befd..13b3dac85d1 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -25,9 +25,6 @@ metadata_conflicting_alloc_error_handler = metadata_conflicting_global_alloc = the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name} -metadata_consider_adding_std = - consider adding the standard library to the sysroot with `x build library --target {$locator_triple}` - metadata_consider_building_std = consider building the standard library from source with `cargo build -Zbuild-std` diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index b6c82376f4e..fca06c0f47c 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -646,18 +646,12 @@ impl IntoDiagnostic<'_> for CannotFindCrate { } else { diag.note(fluent::metadata_target_no_std_support); } - + // NOTE: this suggests using rustup, even though the user may not have it installed. + // That's because they could choose to install it; or this may give them a hint which + // target they need to install from their distro. if self.missing_core { - if env!("CFG_RELEASE_CHANNEL") == "dev" { - diag.help(fluent::metadata_consider_adding_std); - } else { - // NOTE: this suggests using rustup, even though the user may not have it installed. - // That's because they could choose to install it; or this may give them a hint which - // target they need to install from their distro. - diag.help(fluent::metadata_consider_downloading_target); - } + diag.help(fluent::metadata_consider_downloading_target); } - // Suggest using #![no_std]. #[no_core] is unstable and not really supported anyway. // NOTE: this is a dummy span if `extern crate std` was injected by the compiler. // If it's not a dummy, that means someone added `extern crate std` explicitly and diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index efe49d687c9..541c19c3561 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1151,10 +1151,10 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> let assoc_item = tcx.associated_item(def_id); match assoc_item.container { ty::AssocItemContainer::ImplContainer => true, - // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty) always encode RPITITs, - // since we need to be able to "project" from an RPITIT associated item - // to an opaque when installing the default projection predicates in - // default trait methods with RPITITs. + // Always encode RPITITs, since we need to be able to project + // from an RPITIT associated item to an opaque when installing + // the default projection predicates in default trait methods + // with RPITITs. ty::AssocItemContainer::TraitContainer => { assoc_item.defaultness(tcx).has_value() || assoc_item.opt_rpitit_info.is_some() } diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 07ab3ba4e8a..4c238308fe8 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" [dependencies] bitflags = "1.2.1" -chalk-ir = "0.92.0" derive_more = "0.99.17" either = "1.5.0" gsgdt = "0.1.2" diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 1b19ed9ad14..d5e8330b3f6 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -433,7 +433,8 @@ impl<'tcx> CanonicalVarValues<'tcx> { |(i, info)| -> ty::GenericArg<'tcx> { match info.kind { CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => { - tcx.mk_bound(ty::INNERMOST, ty::BoundVar::from_usize(i).into()).into() + Ty::new_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i).into()) + .into() } CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => { let br = ty::BoundRegion { @@ -443,12 +444,13 @@ impl<'tcx> CanonicalVarValues<'tcx> { ty::Region::new_late_bound(tcx, ty::INNERMOST, br).into() } CanonicalVarKind::Const(_, ty) - | CanonicalVarKind::PlaceholderConst(_, ty) => tcx - .mk_const( - ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i)), - ty, - ) - .into(), + | CanonicalVarKind::PlaceholderConst(_, ty) => ty::Const::new_bound( + tcx, + ty::INNERMOST, + ty::BoundVar::from_usize(i), + ty, + ) + .into(), } }, )), diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index 991b9f01985..85fb9214d9d 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -90,15 +90,15 @@ impl<'tcx> UnifyValue for UnifiedRegion<'tcx> { impl ToType for ty::IntVarValue { fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match *self { - ty::IntType(i) => tcx.mk_mach_int(i), - ty::UintType(i) => tcx.mk_mach_uint(i), + ty::IntType(i) => Ty::new_int(tcx, i), + ty::UintType(i) => Ty::new_uint(tcx, i), } } } impl ToType for ty::FloatVarValue { fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - tcx.mk_mach_float(self.0) + Ty::new_float(tcx, self.0) } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index ad1c93c31e9..efb01b0faba 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1913,7 +1913,7 @@ impl<'tcx> Operand<'tcx> { substs: impl IntoIterator<Item = GenericArg<'tcx>>, span: Span, ) -> Self { - let ty = tcx.mk_fn_def(def_id, substs); + let ty = Ty::new_fn_def(tcx, def_id, substs); Operand::Constant(Box::new(Constant { span, user_ty: None, @@ -2329,10 +2329,10 @@ impl<'tcx> ConstantKind<'tcx> { pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self { match self { Self::Ty(c) => { - if let Some(val) = c.kind().try_eval_for_mir(tcx, param_env) { + if let Some(val) = c.try_eval_for_mir(tcx, param_env) { match val { Ok(val) => Self::Val(val, c.ty()), - Err(guar) => Self::Ty(tcx.const_error(self.ty(), guar)), + Err(guar) => Self::Ty(ty::Const::new_error(tcx, guar, self.ty())), } } else { self @@ -2344,7 +2344,9 @@ impl<'tcx> ConstantKind<'tcx> { match tcx.const_eval_resolve(param_env, uneval, None) { Ok(val) => Self::Val(val, ty), Err(ErrorHandled::TooGeneric) => self, - Err(ErrorHandled::Reported(guar)) => Self::Ty(tcx.const_error(ty, guar.into())), + Err(ErrorHandled::Reported(guar)) => { + Self::Ty(ty::Const::new_error(tcx, guar.into(), ty)) + } } } } @@ -2510,7 +2512,7 @@ impl<'tcx> ConstantKind<'tcx> { let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id]; let name = tcx.item_name(def_id); - let ty_const = tcx.mk_const(ty::ParamConst::new(index, name), ty); + let ty_const = ty::Const::new_param(tcx, ty::ParamConst::new(index, name), ty); debug!(?ty_const); return Self::Ty(ty_const); @@ -2774,7 +2776,7 @@ impl<'tcx> Display for ConstantKind<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { match *self { ConstantKind::Ty(c) => pretty_print_const(c, fmt, true), - ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt, true), + ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt), // FIXME(valtrees): Correctly print mir constants. ConstantKind::Unevaluated(..) => { fmt.write_str("_")?; @@ -2804,13 +2806,16 @@ fn pretty_print_byte_str(fmt: &mut Formatter<'_>, byte_str: &[u8]) -> fmt::Resul write!(fmt, "b\"{}\"", byte_str.escape_ascii()) } -fn comma_sep<'tcx>(fmt: &mut Formatter<'_>, elems: Vec<ConstantKind<'tcx>>) -> fmt::Result { +fn comma_sep<'tcx>( + fmt: &mut Formatter<'_>, + elems: Vec<(ConstValue<'tcx>, Ty<'tcx>)>, +) -> fmt::Result { let mut first = true; - for elem in elems { + for (ct, ty) in elems { if !first { fmt.write_str(", ")?; } - fmt.write_str(&format!("{}", elem))?; + pretty_print_const_value(ct, ty, fmt)?; first = false; } Ok(()) @@ -2821,7 +2826,6 @@ fn pretty_print_const_value<'tcx>( ct: ConstValue<'tcx>, ty: Ty<'tcx>, fmt: &mut Formatter<'_>, - print_ty: bool, ) -> fmt::Result { use crate::ty::print::PrettyPrinter; @@ -2865,7 +2869,7 @@ fn pretty_print_const_value<'tcx>( } } (ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => { - let n = n.kind().try_to_bits(tcx.data_layout.pointer_size).unwrap(); + let n = n.try_to_bits(tcx.data_layout.pointer_size).unwrap(); // cast is ok because we already checked for pointer size (32 or 64 bit) above let range = AllocRange { start: offset, size: Size::from_bytes(n) }; let byte_str = alloc.inner().get_bytes_strip_provenance(&tcx, range).unwrap(); @@ -2880,16 +2884,11 @@ fn pretty_print_const_value<'tcx>( // introducing ICEs (e.g. via `layout_of`) from missing bounds. // E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized` // to be able to destructure the tuple into `(0u8, *mut T)` - // - // FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the - // correct `ty::ParamEnv` to allow printing *all* constant values. (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_non_region_param() => { let ct = tcx.lift(ct).unwrap(); let ty = tcx.lift(ty).unwrap(); - if let Some(contents) = tcx.try_destructure_mir_constant( - ty::ParamEnv::reveal_all().and(ConstantKind::Val(ct, ty)), - ) { - let fields = contents.fields.to_vec(); + if let Some(contents) = tcx.try_destructure_mir_constant_for_diagnostics((ct, ty)) { + let fields: Vec<(ConstValue<'_>, Ty<'_>)> = contents.fields.to_vec(); match *ty.kind() { ty::Array(..) => { fmt.write_str("[")?; @@ -2928,12 +2927,14 @@ fn pretty_print_const_value<'tcx>( None => { fmt.write_str(" {{ ")?; let mut first = true; - for (field_def, field) in iter::zip(&variant_def.fields, fields) + for (field_def, (ct, ty)) in + iter::zip(&variant_def.fields, fields) { if !first { fmt.write_str(", ")?; } - fmt.write_str(&format!("{}: {}", field_def.name, field))?; + write!(fmt, "{}: ", field_def.name)?; + pretty_print_const_value(ct, ty, fmt)?; first = false; } fmt.write_str(" }}")?; @@ -2943,20 +2944,13 @@ fn pretty_print_const_value<'tcx>( _ => unreachable!(), } return Ok(()); - } else { - // Fall back to debug pretty printing for invalid constants. - fmt.write_str(&format!("{:?}", ct))?; - if print_ty { - fmt.write_str(&format!(": {}", ty))?; - } - return Ok(()); - }; + } } (ConstValue::Scalar(scalar), _) => { let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); cx.print_alloc_ids = true; let ty = tcx.lift(ty).unwrap(); - cx = cx.pretty_print_const_scalar(scalar, ty, print_ty)?; + cx = cx.pretty_print_const_scalar(scalar, ty)?; fmt.write_str(&cx.into_buffer())?; return Ok(()); } @@ -2971,12 +2965,8 @@ fn pretty_print_const_value<'tcx>( // their fields instead of just dumping the memory. _ => {} } - // fallback - fmt.write_str(&format!("{:?}", ct))?; - if print_ty { - fmt.write_str(&format!(": {}", ty))?; - } - Ok(()) + // Fall back to debug pretty printing for invalid constants. + write!(fmt, "{ct:?}: {ty}") }) } diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 13a1011e328..613b132ff2d 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -1,6 +1,6 @@ //! Values computed by queries that use MIR. -use crate::mir::ConstantKind; +use crate::mir::interpret::ConstValue; use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::UnordSet; @@ -444,7 +444,7 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> { #[derive(Copy, Clone, Debug, HashStable)] pub struct DestructuredConstant<'tcx> { pub variant: Option<VariantIdx>, - pub fields: &'tcx [ConstantKind<'tcx>], + pub fields: &'tcx [(ConstValue<'tcx>, Ty<'tcx>)], } /// Coverage information summarized from a MIR if instrumented for source code coverage (see diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 65dff193c80..8618a531527 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -95,11 +95,13 @@ impl<'tcx> PlaceTy<'tcx> { ProjectionElem::Subslice { from, to, from_end } => { PlaceTy::from_ty(match self.ty.kind() { ty::Slice(..) => self.ty, - ty::Array(inner, _) if !from_end => tcx.mk_array(*inner, (to - from) as u64), + ty::Array(inner, _) if !from_end => { + Ty::new_array(tcx, *inner, (to - from) as u64) + } ty::Array(inner, size) if from_end => { let size = size.eval_target_usize(tcx, param_env); let len = size - from - to; - tcx.mk_array(*inner, len) + Ty::new_array(tcx, *inner, len) } _ => bug!("cannot subslice non-array type: `{:?}`", self), }) @@ -162,16 +164,16 @@ impl<'tcx> Rvalue<'tcx> { match *self { Rvalue::Use(ref operand) => operand.ty(local_decls, tcx), Rvalue::Repeat(ref operand, count) => { - tcx.mk_array_with_const_len(operand.ty(local_decls, tcx), count) + Ty::new_array_with_const_len(tcx, operand.ty(local_decls, tcx), count) } Rvalue::ThreadLocalRef(did) => tcx.thread_local_ptr_ty(did), Rvalue::Ref(reg, bk, ref place) => { let place_ty = place.ty(local_decls, tcx).ty; - tcx.mk_ref(reg, ty::TypeAndMut { ty: place_ty, mutbl: bk.to_mutbl_lossy() }) + Ty::new_ref(tcx, reg, ty::TypeAndMut { ty: place_ty, mutbl: bk.to_mutbl_lossy() }) } Rvalue::AddressOf(mutability, ref place) => { let place_ty = place.ty(local_decls, tcx).ty; - tcx.mk_ptr(ty::TypeAndMut { ty: place_ty, mutbl: mutability }) + Ty::new_ptr(tcx, ty::TypeAndMut { ty: place_ty, mutbl: mutability }) } Rvalue::Len(..) => tcx.types.usize, Rvalue::Cast(.., ty) => ty, @@ -184,7 +186,7 @@ impl<'tcx> Rvalue<'tcx> { let lhs_ty = lhs.ty(local_decls, tcx); let rhs_ty = rhs.ty(local_decls, tcx); let ty = op.ty(tcx, lhs_ty, rhs_ty); - tcx.mk_tup(&[ty, tcx.types.bool]) + Ty::new_tup(tcx, &[ty, tcx.types.bool]) } Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx), Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), @@ -192,17 +194,17 @@ impl<'tcx> Rvalue<'tcx> { tcx.types.usize } Rvalue::Aggregate(ref ak, ref ops) => match **ak { - AggregateKind::Array(ty) => tcx.mk_array(ty, ops.len() as u64), + AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64), AggregateKind::Tuple => { - tcx.mk_tup_from_iter(ops.iter().map(|op| op.ty(local_decls, tcx))) + Ty::new_tup_from_iter(tcx, ops.iter().map(|op| op.ty(local_decls, tcx))) } AggregateKind::Adt(did, _, substs, _, _) => tcx.type_of(did).subst(tcx, substs), - AggregateKind::Closure(did, substs) => tcx.mk_closure(did, substs), + AggregateKind::Closure(did, substs) => Ty::new_closure(tcx, did, substs), AggregateKind::Generator(did, substs, movability) => { - tcx.mk_generator(did, substs, movability) + Ty::new_generator(tcx, did, substs, movability) } }, - Rvalue::ShallowInitBox(_, ty) => tcx.mk_box(ty), + Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty), Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty, } } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index e8f4fca147b..2c481745d98 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -315,7 +315,6 @@ tcx_lifetime! { rustc_middle::mir::interpret::ConstValue, rustc_middle::mir::interpret::GlobalId, rustc_middle::mir::interpret::LitToConstInput, - rustc_middle::traits::ChalkEnvironmentAndGoal, rustc_middle::traits::query::MethodAutoderefStepsResult, rustc_middle::traits::query::type_op::AscribeUserType, rustc_middle::traits::query::type_op::Eq, diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 4006a6cd1cc..0119e07a44e 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -2,6 +2,7 @@ use crate::infer::canonical::Canonical; use crate::mir; +use crate::mir::interpret::ConstValue; use crate::traits; use crate::ty::fast_reject::SimplifiedType; use crate::ty::layout::{TyAndLayout, ValidityRequirement}; @@ -333,6 +334,14 @@ impl<'tcx> Key for (ty::Const<'tcx>, FieldIdx) { } } +impl<'tcx> Key for (ConstValue<'tcx>, Ty<'tcx>) { + type CacheSelector = DefaultCacheSelector<Self>; + + fn default_span(&self, _: TyCtxt<'_>) -> Span { + DUMMY_SP + } +} + impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index c12587845e5..d58a1a65533 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -39,8 +39,8 @@ use crate::traits::query::{ }; use crate::traits::specialization_graph; use crate::traits::{ - CanonicalChalkEnvironmentAndGoal, CodegenObligationError, EvaluationResult, ImplSource, - ObjectSafetyViolation, ObligationCause, OverflowError, WellFormedLoc, + CodegenObligationError, EvaluationResult, ImplSource, ObjectSafetyViolation, ObligationCause, + OverflowError, WellFormedLoc, }; use crate::ty::fast_reject::SimplifiedType; use crate::ty::layout::ValidityRequirement; @@ -881,7 +881,7 @@ rustc_queries! { /// /// Note that we've liberated the late bound regions of function signatures, so /// this can not be used to check whether these types are well formed. - query assumed_wf_types(key: DefId) -> &'tcx ty::List<Ty<'tcx>> { + query assumed_wf_types(key: LocalDefId) -> &'tcx [(Ty<'tcx>, Span)] { desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) } } @@ -1087,11 +1087,13 @@ rustc_queries! { } /// Tries to destructure an `mir::ConstantKind` ADT or array into its variant index - /// and its field values. - query try_destructure_mir_constant( - key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>> + /// and its field values. This should only be used for pretty printing. + query try_destructure_mir_constant_for_diagnostics( + key: (ConstValue<'tcx>, Ty<'tcx>) ) -> Option<mir::DestructuredConstant<'tcx>> { desc { "destructuring MIR constant"} + no_hash + eval_always } query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> { @@ -1971,15 +1973,6 @@ rustc_queries! { desc { "evaluating trait selection obligation `{}`", goal.value.value } } - query evaluate_goal( - goal: CanonicalChalkEnvironmentAndGoal<'tcx> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, - NoSolution - > { - desc { "evaluating trait selection obligation `{}`", goal.value } - } - /// Do not call this query directly: part of the `Eq` type-op query type_op_ascribe_user_type( goal: CanonicalTypeOpAscribeUserTypeGoal<'tcx> @@ -2206,6 +2199,10 @@ rustc_queries! { desc { "getting cfg-ed out item names" } separate_provide_extern } + + query generics_require_sized_self(def_id: DefId) -> bool { + desc { "check whether the item has a `where Self: Sized` bound" } + } } rustc_query_append! { define_callbacks! } diff --git a/compiler/rustc_middle/src/traits/chalk.rs b/compiler/rustc_middle/src/traits/chalk.rs deleted file mode 100644 index 6e3d2d91ae9..00000000000 --- a/compiler/rustc_middle/src/traits/chalk.rs +++ /dev/null @@ -1,396 +0,0 @@ -//! Types required for Chalk-related queries -//! -//! The primary purpose of this file is defining an implementation for the -//! `chalk_ir::interner::Interner` trait. The primary purpose of this trait, as -//! its name suggest, is to provide an abstraction boundary for creating -//! interned Chalk types. - -use rustc_middle::ty::{self, AdtDef, TyCtxt}; - -use rustc_hir::def_id::DefId; -use rustc_target::spec::abi::Abi; - -use std::cmp::Ordering; -use std::fmt; -use std::hash::{Hash, Hasher}; - -#[derive(Copy, Clone)] -pub struct RustInterner<'tcx> { - pub tcx: TyCtxt<'tcx>, -} - -/// We don't ever actually need this. It's only required for derives. -impl<'tcx> Hash for RustInterner<'tcx> { - fn hash<H: Hasher>(&self, _state: &mut H) {} -} - -/// We don't ever actually need this. It's only required for derives. -impl<'tcx> Ord for RustInterner<'tcx> { - fn cmp(&self, _other: &Self) -> Ordering { - Ordering::Equal - } -} - -/// We don't ever actually need this. It's only required for derives. -impl<'tcx> PartialOrd for RustInterner<'tcx> { - fn partial_cmp(&self, _other: &Self) -> Option<Ordering> { - None - } -} - -/// We don't ever actually need this. It's only required for derives. -impl<'tcx> PartialEq for RustInterner<'tcx> { - fn eq(&self, _other: &Self) -> bool { - false - } -} - -/// We don't ever actually need this. It's only required for derives. -impl<'tcx> Eq for RustInterner<'tcx> {} - -impl fmt::Debug for RustInterner<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "RustInterner") - } -} - -// Right now, there is no interning at all. I was running into problems with -// adding interning in `ty/context.rs` for Chalk types with -// `parallel-compiler = true`. -jackh726 -impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> { - type InternedType = Box<chalk_ir::TyData<Self>>; - type InternedLifetime = Box<chalk_ir::LifetimeData<Self>>; - type InternedConst = Box<chalk_ir::ConstData<Self>>; - type InternedConcreteConst = ty::ValTree<'tcx>; - type InternedGenericArg = Box<chalk_ir::GenericArgData<Self>>; - type InternedGoal = Box<chalk_ir::GoalData<Self>>; - type InternedGoals = Vec<chalk_ir::Goal<Self>>; - type InternedSubstitution = Vec<chalk_ir::GenericArg<Self>>; - type InternedProgramClause = Box<chalk_ir::ProgramClauseData<Self>>; - type InternedProgramClauses = Vec<chalk_ir::ProgramClause<Self>>; - type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>; - type InternedVariableKinds = Vec<chalk_ir::VariableKind<Self>>; - type InternedCanonicalVarKinds = Vec<chalk_ir::CanonicalVarKind<Self>>; - type InternedVariances = Vec<chalk_ir::Variance>; - type InternedConstraints = Vec<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>>; - type DefId = DefId; - type InternedAdtId = AdtDef<'tcx>; - type Identifier = (); - type FnAbi = Abi; - - fn debug_program_clause_implication( - pci: &chalk_ir::ProgramClauseImplication<Self>, - fmt: &mut fmt::Formatter<'_>, - ) -> Option<fmt::Result> { - let mut write = || { - write!(fmt, "{:?}", pci.consequence)?; - - let conditions = pci.conditions.interned(); - let constraints = pci.constraints.interned(); - - let conds = conditions.len(); - let consts = constraints.len(); - if conds == 0 && consts == 0 { - return Ok(()); - } - - write!(fmt, " :- ")?; - - if conds != 0 { - for cond in &conditions[..conds - 1] { - write!(fmt, "{:?}, ", cond)?; - } - write!(fmt, "{:?}", conditions[conds - 1])?; - } - - if conds != 0 && consts != 0 { - write!(fmt, " ; ")?; - } - - if consts != 0 { - for constraint in &constraints[..consts - 1] { - write!(fmt, "{:?}, ", constraint)?; - } - write!(fmt, "{:?}", constraints[consts - 1])?; - } - - Ok(()) - }; - Some(write()) - } - - fn debug_substitution( - substitution: &chalk_ir::Substitution<Self>, - fmt: &mut fmt::Formatter<'_>, - ) -> Option<fmt::Result> { - Some(write!(fmt, "{:?}", substitution.interned())) - } - - fn debug_separator_trait_ref( - separator_trait_ref: &chalk_ir::SeparatorTraitRef<'_, Self>, - fmt: &mut fmt::Formatter<'_>, - ) -> Option<fmt::Result> { - let substitution = &separator_trait_ref.trait_ref.substitution; - let parameters = substitution.interned(); - Some(write!( - fmt, - "{:?}{}{:?}{:?}", - parameters[0], - separator_trait_ref.separator, - separator_trait_ref.trait_ref.trait_id, - chalk_ir::debug::Angle(¶meters[1..]) - )) - } - - fn debug_quantified_where_clauses( - clauses: &chalk_ir::QuantifiedWhereClauses<Self>, - fmt: &mut fmt::Formatter<'_>, - ) -> Option<fmt::Result> { - Some(write!(fmt, "{:?}", clauses.interned())) - } - - fn debug_ty(ty: &chalk_ir::Ty<Self>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { - match &ty.interned().kind { - chalk_ir::TyKind::Ref(chalk_ir::Mutability::Not, lifetime, ty) => { - Some(write!(fmt, "(&{:?} {:?})", lifetime, ty)) - } - chalk_ir::TyKind::Ref(chalk_ir::Mutability::Mut, lifetime, ty) => { - Some(write!(fmt, "(&{:?} mut {:?})", lifetime, ty)) - } - chalk_ir::TyKind::Array(ty, len) => Some(write!(fmt, "[{:?}; {:?}]", ty, len)), - chalk_ir::TyKind::Slice(ty) => Some(write!(fmt, "[{:?}]", ty)), - chalk_ir::TyKind::Tuple(len, substs) => Some( - try { - write!(fmt, "(")?; - for (idx, substitution) in substs.interned().iter().enumerate() { - if idx == *len && *len != 1 { - // Don't add a trailing comma if the tuple has more than one element - write!(fmt, "{:?}", substitution)?; - } else { - write!(fmt, "{:?},", substitution)?; - } - } - write!(fmt, ")")?; - }, - ), - _ => None, - } - } - - fn debug_alias( - alias_ty: &chalk_ir::AliasTy<Self>, - fmt: &mut fmt::Formatter<'_>, - ) -> Option<fmt::Result> { - match alias_ty { - chalk_ir::AliasTy::Projection(projection_ty) => { - Self::debug_projection_ty(projection_ty, fmt) - } - chalk_ir::AliasTy::Opaque(opaque_ty) => Self::debug_opaque_ty(opaque_ty, fmt), - } - } - - fn debug_projection_ty( - projection_ty: &chalk_ir::ProjectionTy<Self>, - fmt: &mut fmt::Formatter<'_>, - ) -> Option<fmt::Result> { - Some(write!( - fmt, - "projection: {:?} {:?}", - projection_ty.associated_ty_id, projection_ty.substitution, - )) - } - - fn debug_opaque_ty( - opaque_ty: &chalk_ir::OpaqueTy<Self>, - fmt: &mut fmt::Formatter<'_>, - ) -> Option<fmt::Result> { - Some(write!(fmt, "{:?}", opaque_ty.opaque_ty_id)) - } - - fn intern_ty(self, ty: chalk_ir::TyKind<Self>) -> Self::InternedType { - let flags = ty.compute_flags(self); - Box::new(chalk_ir::TyData { kind: ty, flags: flags }) - } - - fn ty_data(self, ty: &Self::InternedType) -> &chalk_ir::TyData<Self> { - ty - } - - fn intern_lifetime(self, lifetime: chalk_ir::LifetimeData<Self>) -> Self::InternedLifetime { - Box::new(lifetime) - } - - fn lifetime_data(self, lifetime: &Self::InternedLifetime) -> &chalk_ir::LifetimeData<Self> { - &lifetime - } - - fn intern_const(self, constant: chalk_ir::ConstData<Self>) -> Self::InternedConst { - Box::new(constant) - } - - fn const_data(self, constant: &Self::InternedConst) -> &chalk_ir::ConstData<Self> { - &constant - } - - fn const_eq( - self, - _ty: &Self::InternedType, - c1: &Self::InternedConcreteConst, - c2: &Self::InternedConcreteConst, - ) -> bool { - c1 == c2 - } - - fn intern_generic_arg(self, data: chalk_ir::GenericArgData<Self>) -> Self::InternedGenericArg { - Box::new(data) - } - - fn generic_arg_data(self, data: &Self::InternedGenericArg) -> &chalk_ir::GenericArgData<Self> { - &data - } - - fn intern_goal(self, goal: chalk_ir::GoalData<Self>) -> Self::InternedGoal { - Box::new(goal) - } - - fn goal_data(self, goal: &Self::InternedGoal) -> &chalk_ir::GoalData<Self> { - &goal - } - - fn intern_goals<E>( - self, - data: impl IntoIterator<Item = Result<chalk_ir::Goal<Self>, E>>, - ) -> Result<Self::InternedGoals, E> { - data.into_iter().collect::<Result<Vec<_>, _>>() - } - - fn goals_data(self, goals: &Self::InternedGoals) -> &[chalk_ir::Goal<Self>] { - goals - } - - fn intern_substitution<E>( - self, - data: impl IntoIterator<Item = Result<chalk_ir::GenericArg<Self>, E>>, - ) -> Result<Self::InternedSubstitution, E> { - data.into_iter().collect::<Result<Vec<_>, _>>() - } - - fn substitution_data( - self, - substitution: &Self::InternedSubstitution, - ) -> &[chalk_ir::GenericArg<Self>] { - substitution - } - - fn intern_program_clause( - self, - data: chalk_ir::ProgramClauseData<Self>, - ) -> Self::InternedProgramClause { - Box::new(data) - } - - fn program_clause_data( - self, - clause: &Self::InternedProgramClause, - ) -> &chalk_ir::ProgramClauseData<Self> { - &clause - } - - fn intern_program_clauses<E>( - self, - data: impl IntoIterator<Item = Result<chalk_ir::ProgramClause<Self>, E>>, - ) -> Result<Self::InternedProgramClauses, E> { - data.into_iter().collect::<Result<Vec<_>, _>>() - } - - fn program_clauses_data( - self, - clauses: &Self::InternedProgramClauses, - ) -> &[chalk_ir::ProgramClause<Self>] { - clauses - } - - fn intern_quantified_where_clauses<E>( - self, - data: impl IntoIterator<Item = Result<chalk_ir::QuantifiedWhereClause<Self>, E>>, - ) -> Result<Self::InternedQuantifiedWhereClauses, E> { - data.into_iter().collect::<Result<Vec<_>, _>>() - } - - fn quantified_where_clauses_data( - self, - clauses: &Self::InternedQuantifiedWhereClauses, - ) -> &[chalk_ir::QuantifiedWhereClause<Self>] { - clauses - } - - fn intern_generic_arg_kinds<E>( - self, - data: impl IntoIterator<Item = Result<chalk_ir::VariableKind<Self>, E>>, - ) -> Result<Self::InternedVariableKinds, E> { - data.into_iter().collect::<Result<Vec<_>, _>>() - } - - fn variable_kinds_data( - self, - parameter_kinds: &Self::InternedVariableKinds, - ) -> &[chalk_ir::VariableKind<Self>] { - parameter_kinds - } - - fn intern_canonical_var_kinds<E>( - self, - data: impl IntoIterator<Item = Result<chalk_ir::CanonicalVarKind<Self>, E>>, - ) -> Result<Self::InternedCanonicalVarKinds, E> { - data.into_iter().collect::<Result<Vec<_>, _>>() - } - - fn canonical_var_kinds_data( - self, - canonical_var_kinds: &Self::InternedCanonicalVarKinds, - ) -> &[chalk_ir::CanonicalVarKind<Self>] { - canonical_var_kinds - } - - fn intern_constraints<E>( - self, - data: impl IntoIterator<Item = Result<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>, E>>, - ) -> Result<Self::InternedConstraints, E> { - data.into_iter().collect::<Result<Vec<_>, _>>() - } - - fn constraints_data( - self, - constraints: &Self::InternedConstraints, - ) -> &[chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>] { - constraints - } - - fn intern_variances<E>( - self, - data: impl IntoIterator<Item = Result<chalk_ir::Variance, E>>, - ) -> Result<Self::InternedVariances, E> { - data.into_iter().collect::<Result<Vec<_>, _>>() - } - - fn variances_data(self, variances: &Self::InternedVariances) -> &[chalk_ir::Variance] { - variances - } -} - -impl<'tcx> chalk_ir::interner::HasInterner for RustInterner<'tcx> { - type Interner = Self; -} - -/// A chalk environment and goal. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, TypeVisitable)] -pub struct ChalkEnvironmentAndGoal<'tcx> { - pub environment: &'tcx ty::List<ty::Clause<'tcx>>, - pub goal: ty::Predicate<'tcx>, -} - -impl<'tcx> fmt::Display for ChalkEnvironmentAndGoal<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "environment: {:?}, goal: {}", self.environment, self.goal) - } -} diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index a333fbbb506..c7d2e4c22d2 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -2,7 +2,6 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html -mod chalk; pub mod query; pub mod select; pub mod solve; @@ -30,12 +29,8 @@ use std::hash::{Hash, Hasher}; pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; -pub type CanonicalChalkEnvironmentAndGoal<'tcx> = Canonical<'tcx, ChalkEnvironmentAndGoal<'tcx>>; - pub use self::ObligationCauseCode::*; -pub use self::chalk::{ChalkEnvironmentAndGoal, RustInterner as ChalkRustInterner}; - /// Depending on the stage of compilation, we want projection to be /// more or less conservative. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable, Encodable, Decodable)] @@ -593,6 +588,10 @@ pub enum SelectionError<'tcx> { /// Signaling that an error has already been emitted, to avoid /// multiple errors being shown. ErrorReporting, + /// Computing an opaque type's hidden type caused an error (e.g. a cycle error). + /// We can thus not know whether the hidden type implements an auto trait, so + /// we should not presume anything about it. + OpaqueTypeAutoTraitLeakageUnknown(DefId), } #[derive(Clone, Debug, TypeVisitable, Lift)] diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index cbc68fde9d9..09517200b0d 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -81,7 +81,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { Err(TypeError::Sorts(relate::expected_found(self, a, b))) } - (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(self.tcx().ty_error(guar)), + (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(self.tcx(), guar)), _ => relate::structurally_relate_tys(self, a, b), } diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs index a39631da936..ffee7ba28c3 100644 --- a/compiler/rustc_middle/src/ty/abstract_const.rs +++ b/compiler/rustc_middle/src/ty/abstract_const.rs @@ -53,7 +53,7 @@ impl<'tcx> TyCtxt<'tcx> { fn fold_const(&mut self, c: Const<'tcx>) -> Const<'tcx> { let ct = match c.kind() { ty::ConstKind::Unevaluated(uv) => match self.tcx.thir_abstract_const(uv.def) { - Err(e) => self.tcx.const_error(c.ty(), e), + Err(e) => ty::Const::new_error(self.tcx, e, c.ty()), Ok(Some(bac)) => { let substs = self.tcx.erase_regions(uv.substs); let bac = bac.subst(self.tcx, substs); diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index cd0f7e8daf1..a4893684bc8 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -132,7 +132,7 @@ impl<'tcx> OverloadedDeref<'tcx> { .find(|m| m.kind == ty::AssocKind::Fn) .unwrap() .def_id; - tcx.mk_fn_def(method_def_id, [source]) + Ty::new_fn_def(tcx, method_def_id, [source]) } } diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 22bed6ad1c5..6adbb44a153 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -344,7 +344,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Const<'tcx> { fn decode(decoder: &mut D) -> Self { let consts: ty::ConstData<'tcx> = Decodable::decode(decoder); - decoder.interner().mk_const(consts.kind, consts.ty) + decoder.interner().mk_ct_from_kind(consts.kind, consts.ty) } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index aecb46556b0..1cbfe99f87f 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -1,7 +1,8 @@ use crate::middle::resolve_bound_vars as rbv; -use crate::mir::interpret::LitToConstInput; -use crate::ty::{self, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt}; +use crate::mir::interpret::{AllocId, ConstValue, LitToConstInput, Scalar}; +use crate::ty::{self, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; use rustc_data_structures::intern::Interned; +use rustc_error_messages::MultiSpan; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; @@ -13,8 +14,13 @@ mod valtree; pub use int::*; pub use kind::*; +use rustc_span::ErrorGuaranteed; +use rustc_span::DUMMY_SP; +use rustc_target::abi::Size; pub use valtree::*; +use super::sty::ConstKind; + /// Use this rather than `ConstData`, whenever possible. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] #[rustc_pass_by_value] @@ -30,6 +36,16 @@ pub struct ConstData<'tcx> { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(ConstData<'_>, 40); +enum EvalMode { + Typeck, + Mir, +} + +enum EvalResult<'tcx> { + ValTree(ty::ValTree<'tcx>), + ConstVal(ConstValue<'tcx>), +} + impl<'tcx> Const<'tcx> { #[inline] pub fn ty(self) -> Ty<'tcx> { @@ -38,7 +54,98 @@ impl<'tcx> Const<'tcx> { #[inline] pub fn kind(self) -> ConstKind<'tcx> { - self.0.kind + self.0.kind.clone() + } + + #[inline] + pub fn new(tcx: TyCtxt<'tcx>, kind: ty::ConstKind<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + tcx.mk_ct_from_kind(kind, ty) + } + + #[inline] + pub fn new_param(tcx: TyCtxt<'tcx>, param: ty::ParamConst, ty: Ty<'tcx>) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Param(param), ty) + } + + #[inline] + pub fn new_var(tcx: TyCtxt<'tcx>, infer: ty::ConstVid<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Var(infer)), ty) + } + + #[inline] + pub fn new_fresh(tcx: TyCtxt<'tcx>, fresh: u32, ty: Ty<'tcx>) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Fresh(fresh)), ty) + } + + #[inline] + pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Infer(infer), ty) + } + + #[inline] + pub fn new_bound( + tcx: TyCtxt<'tcx>, + debruijn: ty::DebruijnIndex, + var: ty::BoundVar, + ty: Ty<'tcx>, + ) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Bound(debruijn, var), ty) + } + + #[inline] + pub fn new_placeholder( + tcx: TyCtxt<'tcx>, + placeholder: ty::PlaceholderConst<'tcx>, + ty: Ty<'tcx>, + ) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Placeholder(placeholder), ty) + } + + #[inline] + pub fn new_unevaluated( + tcx: TyCtxt<'tcx>, + uv: ty::UnevaluatedConst<'tcx>, + ty: Ty<'tcx>, + ) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Unevaluated(uv), ty) + } + + #[inline] + pub fn new_value(tcx: TyCtxt<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Value(val), ty) + } + + #[inline] + pub fn new_expr(tcx: TyCtxt<'tcx>, expr: ty::Expr<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Expr(expr), ty) + } + + #[inline] + pub fn new_error(tcx: TyCtxt<'tcx>, e: ty::ErrorGuaranteed, ty: Ty<'tcx>) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Error(e), ty) + } + + /// Like [Ty::new_error] but for constants. + #[track_caller] + pub fn new_misc_error(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + Const::new_error_with_message( + tcx, + ty, + DUMMY_SP, + "ty::ConstKind::Error constructed but no error reported", + ) + } + + /// Like [Ty::new_error_with_message] but for constants. + #[track_caller] + pub fn new_error_with_message<S: Into<MultiSpan>>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + span: S, + msg: &'static str, + ) -> Const<'tcx> { + let reported = tcx.sess.delay_span_bug(span, msg); + Const::new_error(tcx, reported, ty) } /// Literals and const generic parameters are eagerly converted to a constant, everything else @@ -60,7 +167,8 @@ impl<'tcx> Const<'tcx> { match Self::try_eval_lit_or_param(tcx, ty, expr) { Some(v) => v, - None => tcx.mk_const( + None => ty::Const::new_unevaluated( + tcx, ty::UnevaluatedConst { def: def.to_def_id(), substs: InternalSubsts::identity_for_item(tcx, def.to_def_id()), @@ -126,13 +234,19 @@ impl<'tcx> Const<'tcx> { let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id]; let name = tcx.item_name(def_id); - Some(tcx.mk_const(ty::ParamConst::new(index, name), param_ty)) + Some(ty::Const::new_param(tcx, ty::ParamConst::new(index, name), param_ty)) + } + Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { + Some(ty::Const::new_bound( + tcx, + debruijn, + ty::BoundVar::from_u32(index), + param_ty, + )) + } + Some(rbv::ResolvedArg::Error(guar)) => { + Some(ty::Const::new_error(tcx, guar, param_ty)) } - Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => Some(tcx.mk_const( - ty::ConstKind::Bound(debruijn, ty::BoundVar::from_u32(index)), - param_ty, - )), - Some(rbv::ResolvedArg::Error(guar)) => Some(tcx.const_error(param_ty, guar)), arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", expr.hir_id), } } @@ -155,7 +269,8 @@ impl<'tcx> Const<'tcx> { .layout_of(ty) .unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e)) .size; - tcx.mk_const( + ty::Const::new_value( + tcx, ty::ValTree::from_scalar_int(ScalarInt::try_from_uint(bits, size).unwrap()), ty.value, ) @@ -164,7 +279,7 @@ impl<'tcx> Const<'tcx> { #[inline] /// Creates an interned zst constant. pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self { - tcx.mk_const(ty::ValTree::zst(), ty) + ty::Const::new_value(tcx, ty::ValTree::zst(), ty) } #[inline] @@ -192,12 +307,12 @@ impl<'tcx> Const<'tcx> { assert_eq!(self.ty(), ty); let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size; // if `ty` does not depend on generic parameters, use an empty param_env - self.kind().eval(tcx, param_env).try_to_bits(size) + self.eval(tcx, param_env).try_to_bits(size) } #[inline] pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> { - self.kind().eval(tcx, param_env).try_to_bool() + self.eval(tcx, param_env).try_to_bool() } #[inline] @@ -206,17 +321,17 @@ impl<'tcx> Const<'tcx> { tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ) -> Option<u64> { - self.kind().eval(tcx, param_env).try_to_target_usize(tcx) + self.eval(tcx, param_env).try_to_target_usize(tcx) } #[inline] /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the /// unevaluated constant. pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Const<'tcx> { - if let Some(val) = self.kind().try_eval_for_typeck(tcx, param_env) { + if let Some(val) = self.try_eval_for_typeck(tcx, param_env) { match val { - Ok(val) => tcx.mk_const(val, self.ty()), - Err(guar) => tcx.const_error(self.ty(), guar), + Ok(val) => ty::Const::new_value(tcx, val, self.ty()), + Err(guar) => ty::Const::new_error(tcx, guar, self.ty()), } } else { // Either the constant isn't evaluatable or ValTree creation failed. @@ -238,6 +353,138 @@ impl<'tcx> Const<'tcx> { .unwrap_or_else(|| bug!("expected usize, got {:#?}", self)) } + #[inline] + /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary + /// return `None`. + // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged. + pub fn try_eval_for_mir( + self, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + ) -> Option<Result<ConstValue<'tcx>, ErrorGuaranteed>> { + match self.try_eval_inner(tcx, param_env, EvalMode::Mir) { + Some(Ok(EvalResult::ValTree(_))) => unreachable!(), + Some(Ok(EvalResult::ConstVal(v))) => Some(Ok(v)), + Some(Err(e)) => Some(Err(e)), + None => None, + } + } + + #[inline] + /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary + /// return `None`. + // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged. + pub fn try_eval_for_typeck( + self, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + ) -> Option<Result<ty::ValTree<'tcx>, ErrorGuaranteed>> { + match self.try_eval_inner(tcx, param_env, EvalMode::Typeck) { + Some(Ok(EvalResult::ValTree(v))) => Some(Ok(v)), + Some(Ok(EvalResult::ConstVal(_))) => unreachable!(), + Some(Err(e)) => Some(Err(e)), + None => None, + } + } + + #[inline] + fn try_eval_inner( + self, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + eval_mode: EvalMode, + ) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> { + assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}"); + if let ConstKind::Unevaluated(unevaluated) = self.kind() { + use crate::mir::interpret::ErrorHandled; + + // HACK(eddyb) this erases lifetimes even though `const_eval_resolve` + // also does later, but we want to do it before checking for + // inference variables. + // Note that we erase regions *before* calling `with_reveal_all_normalized`, + // so that we don't try to invoke this query with + // any region variables. + + // HACK(eddyb) when the query key would contain inference variables, + // attempt using identity substs and `ParamEnv` instead, that will succeed + // when the expression doesn't depend on any parameters. + // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that + // we can call `infcx.const_eval_resolve` which handles inference variables. + let param_env_and = if (param_env, unevaluated).has_non_region_infer() { + tcx.param_env(unevaluated.def).and(ty::UnevaluatedConst { + def: unevaluated.def, + substs: InternalSubsts::identity_for_item(tcx, unevaluated.def), + }) + } else { + tcx.erase_regions(param_env) + .with_reveal_all_normalized(tcx) + .and(tcx.erase_regions(unevaluated)) + }; + + // FIXME(eddyb) maybe the `const_eval_*` methods should take + // `ty::ParamEnvAnd` instead of having them separate. + let (param_env, unevaluated) = param_env_and.into_parts(); + // try to resolve e.g. associated constants to their definition on an impl, and then + // evaluate the const. + match eval_mode { + EvalMode::Typeck => { + match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, None) { + // NOTE(eddyb) `val` contains no lifetimes/types/consts, + // and we use the original type, so nothing from `substs` + // (which may be identity substs, see above), + // can leak through `val` into the const we return. + Ok(val) => Some(Ok(EvalResult::ValTree(val?))), + Err(ErrorHandled::TooGeneric) => None, + Err(ErrorHandled::Reported(e)) => Some(Err(e.into())), + } + } + EvalMode::Mir => { + match tcx.const_eval_resolve(param_env, unevaluated.expand(), None) { + // NOTE(eddyb) `val` contains no lifetimes/types/consts, + // and we use the original type, so nothing from `substs` + // (which may be identity substs, see above), + // can leak through `val` into the const we return. + Ok(val) => Some(Ok(EvalResult::ConstVal(val))), + Err(ErrorHandled::TooGeneric) => None, + Err(ErrorHandled::Reported(e)) => Some(Err(e.into())), + } + } + } + } else { + None + } + } + + #[inline] + pub fn try_to_value(self) -> Option<ty::ValTree<'tcx>> { + if let ConstKind::Value(val) = self.kind() { Some(val) } else { None } + } + + #[inline] + pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> { + self.try_to_value()?.try_to_scalar() + } + + #[inline] + pub fn try_to_scalar_int(self) -> Option<ScalarInt> { + self.try_to_value()?.try_to_scalar_int() + } + + #[inline] + pub fn try_to_bits(self, size: Size) -> Option<u128> { + self.try_to_scalar_int()?.to_bits(size).ok() + } + + #[inline] + pub fn try_to_bool(self) -> Option<bool> { + self.try_to_scalar_int()?.try_into().ok() + } + + #[inline] + pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> { + self.try_to_value()?.try_to_target_usize(tcx) + } + pub fn is_ct_infer(self) -> bool { matches!(self.kind(), ty::ConstKind::Infer(_)) } diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 1dd4f8a2437..a6bf7491118 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -1,17 +1,11 @@ use super::Const; use crate::mir; -use crate::mir::interpret::{AllocId, ConstValue, Scalar}; use crate::ty::abstract_const::CastKind; -use crate::ty::subst::{InternalSubsts, SubstsRef}; -use crate::ty::ParamEnv; -use crate::ty::{self, List, Ty, TyCtxt, TypeVisitableExt}; +use crate::ty::subst::SubstsRef; +use crate::ty::{self, List, Ty}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; -use rustc_target::abi::Size; - -use super::ScalarInt; /// An unevaluated (potentially generic) constant used in the type-system. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)] @@ -41,45 +35,6 @@ impl<'tcx> UnevaluatedConst<'tcx> { } } -/// Represents a constant in Rust. -#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] -#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)] -#[derive(derive_more::From)] -pub enum ConstKind<'tcx> { - /// A const generic parameter. - Param(ty::ParamConst), - - /// Infer the value of the const. - Infer(InferConst<'tcx>), - - /// Bound const variable, used only when preparing a trait query. - Bound(ty::DebruijnIndex, ty::BoundVar), - - /// A placeholder const - universally quantified higher-ranked const. - Placeholder(ty::PlaceholderConst<'tcx>), - - /// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other - /// variants when the code is monomorphic enough for that. - Unevaluated(UnevaluatedConst<'tcx>), - - /// Used to hold computed value. - Value(ty::ValTree<'tcx>), - - /// A placeholder for a const which could not be computed; this is - /// propagated to avoid useless error messages. - #[from(ignore)] - Error(ErrorGuaranteed), - - /// Expr which contains an expression which has partially evaluated items. - Expr(Expr<'tcx>), -} - -impl<'tcx> From<ty::ConstVid<'tcx>> for ConstKind<'tcx> { - fn from(const_vid: ty::ConstVid<'tcx>) -> Self { - InferConst::Var(const_vid).into() - } -} - #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] #[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)] pub enum Expr<'tcx> { @@ -93,39 +48,7 @@ pub enum Expr<'tcx> { static_assert_size!(Expr<'_>, 24); #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(ConstKind<'_>, 32); - -impl<'tcx> ConstKind<'tcx> { - #[inline] - pub fn try_to_value(self) -> Option<ty::ValTree<'tcx>> { - if let ConstKind::Value(val) = self { Some(val) } else { None } - } - - #[inline] - pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> { - self.try_to_value()?.try_to_scalar() - } - - #[inline] - pub fn try_to_scalar_int(self) -> Option<ScalarInt> { - self.try_to_value()?.try_to_scalar_int() - } - - #[inline] - pub fn try_to_bits(self, size: Size) -> Option<u128> { - self.try_to_scalar_int()?.to_bits(size).ok() - } - - #[inline] - pub fn try_to_bool(self) -> Option<bool> { - self.try_to_scalar_int()?.try_into().ok() - } - - #[inline] - pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> { - self.try_to_value()?.try_to_target_usize(tcx) - } -} +static_assert_size!(super::ConstKind<'_>, 32); /// An inference variable for a const, for use in const generics. #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)] @@ -144,124 +67,3 @@ impl<CTX> HashStable<CTX> for InferConst<'_> { } } } - -enum EvalMode { - Typeck, - Mir, -} - -enum EvalResult<'tcx> { - ValTree(ty::ValTree<'tcx>), - ConstVal(ConstValue<'tcx>), -} - -impl<'tcx> ConstKind<'tcx> { - #[inline] - /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the - /// unevaluated constant. - pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self { - self.try_eval_for_typeck(tcx, param_env).and_then(Result::ok).map_or(self, ConstKind::Value) - } - - #[inline] - /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary - /// return `None`. - // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged. - pub fn try_eval_for_mir( - self, - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - ) -> Option<Result<ConstValue<'tcx>, ErrorGuaranteed>> { - match self.try_eval_inner(tcx, param_env, EvalMode::Mir) { - Some(Ok(EvalResult::ValTree(_))) => unreachable!(), - Some(Ok(EvalResult::ConstVal(v))) => Some(Ok(v)), - Some(Err(e)) => Some(Err(e)), - None => None, - } - } - - #[inline] - /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary - /// return `None`. - // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged. - pub fn try_eval_for_typeck( - self, - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - ) -> Option<Result<ty::ValTree<'tcx>, ErrorGuaranteed>> { - match self.try_eval_inner(tcx, param_env, EvalMode::Typeck) { - Some(Ok(EvalResult::ValTree(v))) => Some(Ok(v)), - Some(Ok(EvalResult::ConstVal(_))) => unreachable!(), - Some(Err(e)) => Some(Err(e)), - None => None, - } - } - - #[inline] - fn try_eval_inner( - self, - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - eval_mode: EvalMode, - ) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> { - assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}"); - if let ConstKind::Unevaluated(unevaluated) = self { - use crate::mir::interpret::ErrorHandled; - - // HACK(eddyb) this erases lifetimes even though `const_eval_resolve` - // also does later, but we want to do it before checking for - // inference variables. - // Note that we erase regions *before* calling `with_reveal_all_normalized`, - // so that we don't try to invoke this query with - // any region variables. - - // HACK(eddyb) when the query key would contain inference variables, - // attempt using identity substs and `ParamEnv` instead, that will succeed - // when the expression doesn't depend on any parameters. - // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that - // we can call `infcx.const_eval_resolve` which handles inference variables. - let param_env_and = if (param_env, unevaluated).has_non_region_infer() { - tcx.param_env(unevaluated.def).and(ty::UnevaluatedConst { - def: unevaluated.def, - substs: InternalSubsts::identity_for_item(tcx, unevaluated.def), - }) - } else { - tcx.erase_regions(param_env) - .with_reveal_all_normalized(tcx) - .and(tcx.erase_regions(unevaluated)) - }; - - // FIXME(eddyb) maybe the `const_eval_*` methods should take - // `ty::ParamEnvAnd` instead of having them separate. - let (param_env, unevaluated) = param_env_and.into_parts(); - // try to resolve e.g. associated constants to their definition on an impl, and then - // evaluate the const. - match eval_mode { - EvalMode::Typeck => { - match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, None) { - // NOTE(eddyb) `val` contains no lifetimes/types/consts, - // and we use the original type, so nothing from `substs` - // (which may be identity substs, see above), - // can leak through `val` into the const we return. - Ok(val) => Some(Ok(EvalResult::ValTree(val?))), - Err(ErrorHandled::TooGeneric) => None, - Err(ErrorHandled::Reported(e)) => Some(Err(e.into())), - } - } - EvalMode::Mir => { - match tcx.const_eval_resolve(param_env, unevaluated.expand(), None) { - // NOTE(eddyb) `val` contains no lifetimes/types/consts, - // and we use the original type, so nothing from `substs` - // (which may be identity substs, see above), - // can leak through `val` into the const we return. - Ok(val) => Some(Ok(EvalResult::ConstVal(val))), - Err(ErrorHandled::TooGeneric) => None, - Err(ErrorHandled::Reported(e)) => Some(Err(e.into())), - } - } - } - } else { - None - } - } -} diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 1c610d6891b..035e978f64c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -25,10 +25,10 @@ use crate::traits::solve::{ ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, PredefinedOpaquesData, }; use crate::ty::{ - self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Const, ConstData, FloatTy, FloatVar, - FloatVid, GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst, - ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, - ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy, Visibility, + self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Const, ConstData, GenericParamDefKind, + ImplPolarity, InferTy, List, ParamConst, ParamTy, PolyExistentialPredicate, PolyFnSig, + Predicate, PredicateKind, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, + TyVid, TypeAndMut, Visibility, }; use crate::ty::{GenericArg, InternalSubsts, SubstsRef}; use rustc_ast::{self as ast, attr}; @@ -70,10 +70,9 @@ use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx} use rustc_target::spec::abi; use rustc_type_ir::sty::TyKind::*; use rustc_type_ir::WithCachedTypeInfo; -use rustc_type_ir::{CollectAndApply, DynKind, Interner, TypeFlags}; +use rustc_type_ir::{CollectAndApply, Interner, TypeFlags}; use std::any::Any; -use std::assert_matches::debug_assert_matches; use std::borrow::Borrow; use std::cmp::Ordering; use std::fmt; @@ -108,6 +107,14 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type PredicateKind = ty::PredicateKind<'tcx>; type AllocId = crate::mir::interpret::AllocId; + type InferConst = ty::InferConst<'tcx>; + type AliasConst = ty::UnevaluatedConst<'tcx>; + type ParamConst = ty::ParamConst; + type BoundConst = ty::BoundVar; + type PlaceholderConst = ty::PlaceholderConst<'tcx>; + type ValueConst = ty::ValTree<'tcx>; + type ExprConst = ty::Expr<'tcx>; + type EarlyBoundRegion = ty::EarlyBoundRegion; type BoundRegion = ty::BoundRegion; type FreeRegion = ty::FreeRegion; @@ -320,6 +327,8 @@ pub struct CommonLifetimes<'tcx> { pub struct CommonConsts<'tcx> { pub unit: Const<'tcx>, + pub true_: Const<'tcx>, + pub false_: Const<'tcx>, } impl<'tcx> CommonTypes<'tcx> { @@ -417,6 +426,14 @@ impl<'tcx> CommonConsts<'tcx> { kind: ty::ConstKind::Value(ty::ValTree::zst()), ty: types.unit, }), + true_: mk_const(ty::ConstData { + kind: ty::ConstKind::Value(ty::ValTree::Leaf(ty::ScalarInt::TRUE)), + ty: types.bool, + }), + false_: mk_const(ty::ConstData { + kind: ty::ConstKind::Value(ty::ValTree::Leaf(ty::ScalarInt::FALSE)), + ty: types.bool, + }), } } } @@ -709,58 +726,6 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// Constructs a `TyKind::Error` type with current `ErrorGuaranteed` - #[track_caller] - pub fn ty_error(self, reported: ErrorGuaranteed) -> Ty<'tcx> { - self.mk_ty_from_kind(Error(reported)) - } - - /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used. - #[track_caller] - pub fn ty_error_misc(self) -> Ty<'tcx> { - self.ty_error_with_message(DUMMY_SP, "TyKind::Error constructed but no error reported") - } - - /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to - /// ensure it gets used. - #[track_caller] - pub fn ty_error_with_message<S: Into<MultiSpan>>( - self, - span: S, - msg: impl Into<DiagnosticMessage>, - ) -> Ty<'tcx> { - let reported = self.sess.delay_span_bug(span, msg); - self.mk_ty_from_kind(Error(reported)) - } - - /// Like [TyCtxt::ty_error] but for constants, with current `ErrorGuaranteed` - #[track_caller] - pub fn const_error(self, ty: Ty<'tcx>, reported: ErrorGuaranteed) -> Const<'tcx> { - self.mk_const(ty::ConstKind::Error(reported), ty) - } - - /// Like [TyCtxt::ty_error] but for constants. - #[track_caller] - pub fn const_error_misc(self, ty: Ty<'tcx>) -> Const<'tcx> { - self.const_error_with_message( - ty, - DUMMY_SP, - "ty::ConstKind::Error constructed but no error reported", - ) - } - - /// Like [TyCtxt::ty_error_with_message] but for constants. - #[track_caller] - pub fn const_error_with_message<S: Into<MultiSpan>>( - self, - ty: Ty<'tcx>, - span: S, - msg: &'static str, - ) -> Const<'tcx> { - let reported = self.sess.delay_span_bug(span, msg); - self.mk_const(ty::ConstKind::Error(reported), ty) - } - pub fn consider_optimizing<T: Fn() -> String>(self, msg: T) -> bool { self.sess.consider_optimizing(|| self.crate_name(LOCAL_CRATE), msg) } @@ -1154,7 +1119,8 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns `&'static core::panic::Location<'static>`. pub fn caller_location_ty(self) -> Ty<'tcx> { - self.mk_imm_ref( + Ty::new_imm_ref( + self, self.lifetimes.re_static, self.type_of(self.require_lang_item(LangItem::PanicLocation, None)) .subst(self, self.mk_substs(&[self.lifetimes.re_static.into()])), @@ -1552,7 +1518,10 @@ impl<'tcx> TyCtxt<'tcx> { /// unsafe. pub fn safe_to_unsafe_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> { assert_eq!(sig.unsafety(), hir::Unsafety::Normal); - self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig })) + Ty::new_fn_ptr( + self, + sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig }), + ) } /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name` @@ -1626,18 +1595,6 @@ impl<'tcx> TyCtxt<'tcx> { }) } - // Avoid this in favour of more specific `mk_*` methods, where possible. - #[allow(rustc::usage_of_ty_tykind)] - #[inline] - pub fn mk_ty_from_kind(self, st: TyKind<'tcx>) -> Ty<'tcx> { - self.interners.intern_ty( - st, - self.sess, - // This is only used to create a stable hashing context. - &self.untracked, - ) - } - #[inline] pub fn mk_predicate(self, binder: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> { self.interners.intern_predicate( @@ -1657,174 +1614,6 @@ impl<'tcx> TyCtxt<'tcx> { if pred.kind() != binder { self.mk_predicate(binder) } else { pred } } - pub fn mk_mach_int(self, tm: IntTy) -> Ty<'tcx> { - match tm { - IntTy::Isize => self.types.isize, - IntTy::I8 => self.types.i8, - IntTy::I16 => self.types.i16, - IntTy::I32 => self.types.i32, - IntTy::I64 => self.types.i64, - IntTy::I128 => self.types.i128, - } - } - - pub fn mk_mach_uint(self, tm: UintTy) -> Ty<'tcx> { - match tm { - UintTy::Usize => self.types.usize, - UintTy::U8 => self.types.u8, - UintTy::U16 => self.types.u16, - UintTy::U32 => self.types.u32, - UintTy::U64 => self.types.u64, - UintTy::U128 => self.types.u128, - } - } - - pub fn mk_mach_float(self, tm: FloatTy) -> Ty<'tcx> { - match tm { - FloatTy::F32 => self.types.f32, - FloatTy::F64 => self.types.f64, - } - } - - #[inline] - pub fn mk_static_str(self) -> Ty<'tcx> { - self.mk_imm_ref(self.lifetimes.re_static, self.types.str_) - } - - #[inline] - pub fn mk_adt(self, def: AdtDef<'tcx>, substs: SubstsRef<'tcx>) -> Ty<'tcx> { - // Take a copy of substs so that we own the vectors inside. - self.mk_ty_from_kind(Adt(def, substs)) - } - - #[inline] - pub fn mk_foreign(self, def_id: DefId) -> Ty<'tcx> { - self.mk_ty_from_kind(Foreign(def_id)) - } - - fn mk_generic_adt(self, wrapper_def_id: DefId, ty_param: Ty<'tcx>) -> Ty<'tcx> { - let adt_def = self.adt_def(wrapper_def_id); - let substs = - InternalSubsts::for_item(self, wrapper_def_id, |param, substs| match param.kind { - GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => bug!(), - GenericParamDefKind::Type { has_default, .. } => { - if param.index == 0 { - ty_param.into() - } else { - assert!(has_default); - self.type_of(param.def_id).subst(self, substs).into() - } - } - }); - self.mk_ty_from_kind(Adt(adt_def, substs)) - } - - #[inline] - pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> { - let def_id = self.require_lang_item(LangItem::OwnedBox, None); - self.mk_generic_adt(def_id, ty) - } - - #[inline] - pub fn mk_lang_item(self, ty: Ty<'tcx>, item: LangItem) -> Option<Ty<'tcx>> { - let def_id = self.lang_items().get(item)?; - Some(self.mk_generic_adt(def_id, ty)) - } - - #[inline] - pub fn mk_diagnostic_item(self, ty: Ty<'tcx>, name: Symbol) -> Option<Ty<'tcx>> { - let def_id = self.get_diagnostic_item(name)?; - Some(self.mk_generic_adt(def_id, ty)) - } - - #[inline] - pub fn mk_maybe_uninit(self, ty: Ty<'tcx>) -> Ty<'tcx> { - let def_id = self.require_lang_item(LangItem::MaybeUninit, None); - self.mk_generic_adt(def_id, ty) - } - - #[inline] - pub fn mk_ptr(self, tm: TypeAndMut<'tcx>) -> Ty<'tcx> { - self.mk_ty_from_kind(RawPtr(tm)) - } - - #[inline] - pub fn mk_ref(self, r: Region<'tcx>, tm: TypeAndMut<'tcx>) -> Ty<'tcx> { - self.mk_ty_from_kind(Ref(r, tm.ty, tm.mutbl)) - } - - #[inline] - pub fn mk_mut_ref(self, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ref(r, TypeAndMut { ty, mutbl: hir::Mutability::Mut }) - } - - #[inline] - pub fn mk_imm_ref(self, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ref(r, TypeAndMut { ty, mutbl: hir::Mutability::Not }) - } - - #[inline] - pub fn mk_mut_ptr(self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ptr(TypeAndMut { ty, mutbl: hir::Mutability::Mut }) - } - - #[inline] - pub fn mk_imm_ptr(self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ptr(TypeAndMut { ty, mutbl: hir::Mutability::Not }) - } - - #[inline] - pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> { - self.mk_ty_from_kind(Array(ty, ty::Const::from_target_usize(self, n))) - } - - #[inline] - pub fn mk_array_with_const_len(self, ty: Ty<'tcx>, ct: Const<'tcx>) -> Ty<'tcx> { - self.mk_ty_from_kind(Array(ty, ct)) - } - - #[inline] - pub fn mk_slice(self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ty_from_kind(Slice(ty)) - } - - #[inline] - pub fn mk_tup(self, ts: &[Ty<'tcx>]) -> Ty<'tcx> { - if ts.is_empty() { - self.types.unit - } else { - self.mk_ty_from_kind(Tuple(self.mk_type_list(&ts))) - } - } - - pub fn mk_tup_from_iter<I, T>(self, iter: I) -> T::Output - where - I: Iterator<Item = T>, - T: CollectAndApply<Ty<'tcx>, Ty<'tcx>>, - { - T::collect_and_apply(iter, |ts| self.mk_tup(ts)) - } - - #[inline] - pub fn mk_unit(self) -> Ty<'tcx> { - self.types.unit - } - - #[inline] - pub fn mk_diverging_default(self) -> Ty<'tcx> { - if self.features().never_type_fallback { self.types.never } else { self.types.unit } - } - - #[inline] - pub fn mk_fn_def( - self, - def_id: DefId, - substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>, - ) -> Ty<'tcx> { - let substs = self.check_and_mk_substs(def_id, substs); - self.mk_ty_from_kind(FnDef(def_id, substs)) - } - #[inline(always)] pub(crate) fn check_and_mk_substs( self, @@ -1856,131 +1645,20 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] - pub fn mk_fn_ptr(self, fty: PolyFnSig<'tcx>) -> Ty<'tcx> { - self.mk_ty_from_kind(FnPtr(fty)) - } - - #[inline] - pub fn mk_dynamic( - self, - obj: &'tcx List<PolyExistentialPredicate<'tcx>>, - reg: ty::Region<'tcx>, - repr: DynKind, - ) -> Ty<'tcx> { - self.mk_ty_from_kind(Dynamic(obj, reg, repr)) - } - - #[inline] - pub fn mk_projection( - self, - item_def_id: DefId, - substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>, - ) -> Ty<'tcx> { - self.mk_alias(ty::Projection, self.mk_alias_ty(item_def_id, substs)) - } - - #[inline] - pub fn mk_closure(self, def_id: DefId, closure_substs: SubstsRef<'tcx>) -> Ty<'tcx> { - debug_assert_eq!( - closure_substs.len(), - self.generics_of(self.typeck_root_def_id(def_id)).count() + 3, - "closure constructed with incorrect substitutions" - ); - self.mk_ty_from_kind(Closure(def_id, closure_substs)) - } - - #[inline] - pub fn mk_generator( - self, - def_id: DefId, - generator_substs: SubstsRef<'tcx>, - movability: hir::Movability, - ) -> Ty<'tcx> { - debug_assert_eq!( - generator_substs.len(), - self.generics_of(self.typeck_root_def_id(def_id)).count() + 5, - "generator constructed with incorrect number of substitutions" - ); - self.mk_ty_from_kind(Generator(def_id, generator_substs, movability)) - } - - #[inline] - pub fn mk_generator_witness(self, types: ty::Binder<'tcx, &'tcx List<Ty<'tcx>>>) -> Ty<'tcx> { - self.mk_ty_from_kind(GeneratorWitness(types)) - } - - /// Creates a `&mut Context<'_>` [`Ty`] with erased lifetimes. - pub fn mk_task_context(self) -> Ty<'tcx> { - let context_did = self.require_lang_item(LangItem::Context, None); - let context_adt_ref = self.adt_def(context_did); - let context_substs = self.mk_substs(&[self.lifetimes.re_erased.into()]); - let context_ty = self.mk_adt(context_adt_ref, context_substs); - self.mk_mut_ref(self.lifetimes.re_erased, context_ty) - } - - #[inline] - pub fn mk_generator_witness_mir(self, id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> { - self.mk_ty_from_kind(GeneratorWitnessMIR(id, substs)) - } - - #[inline] - pub fn mk_const(self, kind: impl Into<ty::ConstKind<'tcx>>, ty: Ty<'tcx>) -> Const<'tcx> { - self.intern_const(ty::ConstData { kind: kind.into(), ty }) - } - - #[inline] - pub fn mk_ty_var(self, v: TyVid) -> Ty<'tcx> { - // Use a pre-interned one when possible. - self.types - .ty_vars - .get(v.as_usize()) - .copied() - .unwrap_or_else(|| self.mk_ty_from_kind(Infer(TyVar(v)))) - } - - #[inline] - pub fn mk_int_var(self, v: IntVid) -> Ty<'tcx> { - self.mk_ty_from_kind(Infer(IntVar(v))) - } - - #[inline] - pub fn mk_float_var(self, v: FloatVid) -> Ty<'tcx> { - self.mk_ty_from_kind(Infer(FloatVar(v))) - } - - #[inline] - pub fn mk_fresh_ty(self, n: u32) -> Ty<'tcx> { - // Use a pre-interned one when possible. - self.types - .fresh_tys - .get(n as usize) - .copied() - .unwrap_or_else(|| self.mk_ty_from_kind(Infer(ty::FreshTy(n)))) - } - - #[inline] - pub fn mk_fresh_int_ty(self, n: u32) -> Ty<'tcx> { - // Use a pre-interned one when possible. - self.types - .fresh_int_tys - .get(n as usize) - .copied() - .unwrap_or_else(|| self.mk_ty_from_kind(Infer(ty::FreshIntTy(n)))) - } - - #[inline] - pub fn mk_fresh_float_ty(self, n: u32) -> Ty<'tcx> { - // Use a pre-interned one when possible. - self.types - .fresh_float_tys - .get(n as usize) - .copied() - .unwrap_or_else(|| self.mk_ty_from_kind(Infer(ty::FreshFloatTy(n)))) + pub fn mk_ct_from_kind(self, kind: ty::ConstKind<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + self.intern_const(ty::ConstData { kind, ty }) } + // Avoid this in favour of more specific `Ty::new_*` methods, where possible. + #[allow(rustc::usage_of_ty_tykind)] #[inline] - pub fn mk_ty_param(self, index: u32, name: Symbol) -> Ty<'tcx> { - self.mk_ty_from_kind(Param(ParamTy { index, name })) + pub fn mk_ty_from_kind(self, st: TyKind<'tcx>) -> Ty<'tcx> { + self.interners.intern_ty( + st, + self.sess, + // This is only used to create a stable hashing context. + &self.untracked, + ) } pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> GenericArg<'tcx> { @@ -1988,45 +1666,18 @@ impl<'tcx> TyCtxt<'tcx> { GenericParamDefKind::Lifetime => { ty::Region::new_early_bound(self, param.to_early_bound_region_data()).into() } - GenericParamDefKind::Type { .. } => self.mk_ty_param(param.index, param.name).into(), - GenericParamDefKind::Const { .. } => self - .mk_const( - ParamConst { index: param.index, name: param.name }, - self.type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), - ) - .into(), + GenericParamDefKind::Type { .. } => Ty::new_param(self, param.index, param.name).into(), + GenericParamDefKind::Const { .. } => ty::Const::new_param( + self, + ParamConst { index: param.index, name: param.name }, + self.type_of(param.def_id) + .no_bound_vars() + .expect("const parameter types cannot be generic"), + ) + .into(), } } - #[inline] - pub fn mk_bound(self, index: ty::DebruijnIndex, bound_ty: ty::BoundTy) -> Ty<'tcx> { - self.mk_ty_from_kind(Bound(index, bound_ty)) - } - - #[inline] - pub fn mk_placeholder(self, placeholder: ty::PlaceholderType) -> Ty<'tcx> { - self.mk_ty_from_kind(Placeholder(placeholder)) - } - - #[inline] - pub fn mk_alias(self, kind: ty::AliasKind, alias_ty: ty::AliasTy<'tcx>) -> Ty<'tcx> { - debug_assert_matches!( - (kind, self.def_kind(alias_ty.def_id)), - (ty::Opaque, DefKind::OpaqueTy) - | (ty::Projection | ty::Inherent, DefKind::AssocTy) - | (ty::Opaque | ty::Projection, DefKind::ImplTraitPlaceholder) - | (ty::Weak, DefKind::TyAlias) - ); - self.mk_ty_from_kind(Alias(kind, alias_ty)) - } - - #[inline] - pub fn mk_opaque(self, def_id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> { - self.mk_alias(ty::Opaque, self.mk_alias_ty(def_id, substs)) - } - pub fn mk_place_field(self, place: Place<'tcx>, f: FieldIdx, ty: Ty<'tcx>) -> Place<'tcx> { self.mk_place_elem(place, PlaceElem::Field(f, ty)) } @@ -2377,21 +2028,6 @@ impl<'tcx> TyCtxt<'tcx> { } } -impl<'tcx> TyCtxtAt<'tcx> { - /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used. - #[track_caller] - pub fn ty_error_misc(self) -> Ty<'tcx> { - self.tcx.ty_error_with_message(self.span, "TyKind::Error constructed but no error reported") - } - - /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to - /// ensure it gets used. - #[track_caller] - pub fn ty_error_with_message(self, msg: impl Into<DiagnosticMessage>) -> Ty<'tcx> { - self.tcx.ty_error_with_message(self.span, msg) - } -} - /// Parameter attributes that can only be determined by examining the body of a function instead /// of just its signature. /// diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index d89baa9c88d..a0b17c374e4 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -559,7 +559,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> { Infer(InferTy::TyVar(_)) if self.infer_suggestable => t, FnDef(def_id, substs) => { - self.tcx.mk_fn_ptr(self.tcx.fn_sig(def_id).subst(self.tcx, substs)) + Ty::new_fn_ptr(self.tcx, self.tcx.fn_sig(def_id).subst(self.tcx, substs)) } // FIXME(compiler-errors): We could replace these with infer, I guess. diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 06a8e34cbab..ff391794703 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -287,9 +287,6 @@ impl FlagComputation { self.add_const(expected); self.add_const(found); } - ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(ty)) => { - self.add_ty(ty); - } ty::PredicateKind::Ambiguous => {} ty::PredicateKind::AliasRelate(t1, t2, _) => { self.add_term(t1); diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 149ce29b8d9..77cf6bee79d 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -348,10 +348,14 @@ impl<'tcx> TyCtxt<'tcx> { ) }, types: &mut |t: ty::BoundTy| { - self.mk_bound(ty::INNERMOST, ty::BoundTy { var: shift_bv(t.var), kind: t.kind }) + Ty::new_bound( + self, + ty::INNERMOST, + ty::BoundTy { var: shift_bv(t.var), kind: t.kind }, + ) }, consts: &mut |c, ty: Ty<'tcx>| { - self.mk_const(ty::ConstKind::Bound(ty::INNERMOST, shift_bv(c)), ty) + ty::Const::new_bound(self, ty::INNERMOST, shift_bv(c), ty) }, }, ) @@ -393,14 +397,14 @@ impl<'tcx> TyCtxt<'tcx> { let kind = entry .or_insert_with(|| ty::BoundVariableKind::Ty(ty::BoundTyKind::Anon)) .expect_ty(); - self.tcx.mk_bound(ty::INNERMOST, BoundTy { var, kind }) + Ty::new_bound(self.tcx, ty::INNERMOST, BoundTy { var, kind }) } fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx> { let entry = self.map.entry(bv); let index = entry.index(); let var = ty::BoundVar::from_usize(index); let () = entry.or_insert_with(|| ty::BoundVariableKind::Const).expect_const(); - self.tcx.mk_const(ty::ConstKind::Bound(ty::INNERMOST, var), ty) + ty::Const::new_bound(self.tcx, ty::INNERMOST, var, ty) } } @@ -462,7 +466,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Shifter<'tcx> { match *ty.kind() { ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => { let debruijn = debruijn.shifted_in(self.amount); - self.tcx.mk_bound(debruijn, bound_ty) + Ty::new_bound(self.tcx, debruijn, bound_ty) } _ if ty.has_vars_bound_at_or_above(self.current_index) => ty.super_fold_with(self), @@ -475,7 +479,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Shifter<'tcx> { && debruijn >= self.current_index { let debruijn = debruijn.shifted_in(self.amount); - self.tcx.mk_const(ty::ConstKind::Bound(debruijn, bound_ct), ct.ty()) + ty::Const::new_bound(self.tcx, debruijn, bound_ct, ct.ty()) } else { ct.super_fold_with(self) } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 58fd6e1aa27..6c7125c4cb7 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId; use rustc_span::symbol::{kw, Symbol}; use rustc_span::Span; -use super::{Clause, EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, TyCtxt}; +use super::{Clause, EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Ty, TyCtxt}; #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] pub enum GenericParamDefKind { @@ -101,10 +101,12 @@ impl GenericParamDef { ) -> ty::GenericArg<'tcx> { match &self.kind { ty::GenericParamDefKind::Lifetime => ty::Region::new_error_misc(tcx).into(), - ty::GenericParamDefKind::Type { .. } => tcx.ty_error_misc().into(), - ty::GenericParamDefKind::Const { .. } => { - tcx.const_error_misc(tcx.type_of(self.def_id).subst(tcx, preceding_substs)).into() - } + ty::GenericParamDefKind::Type { .. } => Ty::new_misc_error(tcx).into(), + ty::GenericParamDefKind::Const { .. } => ty::Const::new_misc_error( + tcx, + tcx.type_of(self.def_id).subst(tcx, preceding_substs), + ) + .into(), } } } @@ -133,6 +135,9 @@ pub struct Generics { pub has_self: bool, pub has_late_bound_regions: Option<Span>, + + // The index of the host effect when substituted. (i.e. might be index to parent substs) + pub host_effect_index: Option<usize>, } impl<'tcx> Generics { diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs index 018fa227154..295cb146461 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs @@ -170,7 +170,7 @@ impl<'tcx> InhabitedPredicate<'tcx> { match self { Self::ConstIsZero(c) => { let c = ty::EarlyBinder::bind(c).subst(tcx, substs); - let pred = match c.kind().try_to_target_usize(tcx) { + let pred = match c.try_to_target_usize(tcx) { Some(0) => Self::True, Some(1..) => Self::False, None => Self::ConstIsZero(c), diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 4223502848e..b92d84152b4 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -197,7 +197,7 @@ fn inhabited_predicate_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> InhabitedP // If we can evaluate the array length before having a `ParamEnv`, then // we can simplify the predicate. This is an optimization. - Array(ty, len) => match len.kind().try_to_target_usize(tcx) { + Array(ty, len) => match len.try_to_target_usize(tcx) { Some(0) => InhabitedPredicate::True, Some(1..) => ty.inhabited_predicate(tcx), None => ty.inhabited_predicate(tcx).or(tcx, InhabitedPredicate::ConstIsZero(len)), diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index c0d591430f7..ae57e954ff4 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -410,8 +410,8 @@ impl<'tcx> Instance<'tcx> { ) -> Instance<'tcx> { match ty::Instance::resolve(tcx, param_env, def_id, substs) { Ok(Some(instance)) => instance, - _ => bug!( - "failed to resolve instance for {}", + instance => bug!( + "failed to resolve instance for {}: {instance:#?}", tcx.def_path_str_with_substs(def_id, substs) ), } @@ -552,7 +552,7 @@ impl<'tcx> Instance<'tcx> { tcx.codegen_fn_attrs(closure_did).flags.contains(CodegenFnAttrFlags::TRACK_CALLER); let def = ty::InstanceDef::ClosureOnceShim { call_once, track_caller }; - let self_ty = tcx.mk_closure(closure_did, substs); + let self_ty = Ty::new_closure(tcx, closure_did, substs); let sig = substs.as_closure().sig(); let sig = @@ -680,7 +680,7 @@ fn polymorphize<'tcx>( if substs == polymorphized_substs { ty } else { - self.tcx.mk_closure(def_id, polymorphized_substs) + Ty::new_closure(self.tcx, def_id, polymorphized_substs) } } ty::Generator(def_id, substs, movability) => { @@ -689,7 +689,7 @@ fn polymorphize<'tcx>( if substs == polymorphized_substs { ty } else { - self.tcx.mk_generator(def_id, polymorphized_substs, movability) + Ty::new_generator(self.tcx, def_id, polymorphized_substs, movability) } } _ => ty.super_fold_with(self), diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 9485106e95e..0fe801ad2ed 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2,7 +2,7 @@ use crate::error::UnsupportedFnAbi; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::query::TyCtxtAt; use crate::ty::normalize_erasing_regions::NormalizationError; -use crate::ty::{self, ReprOptions, Ty, TyCtxt, TypeVisitableExt}; +use crate::ty::{self, ConstKind, ReprOptions, Ty, TyCtxt, TypeVisitableExt}; use rustc_error_messages::DiagnosticMessage; use rustc_errors::{DiagnosticBuilder, Handler, IntoDiagnostic}; use rustc_hir as hir; @@ -133,7 +133,7 @@ impl PrimitiveExt for Primitive { F32 => tcx.types.f32, F64 => tcx.types.f64, // FIXME(erikdesjardins): handle non-default addrspace ptr sizes - Pointer(_) => tcx.mk_mut_ptr(tcx.mk_unit()), + Pointer(_) => Ty::new_mut_ptr(tcx, Ty::new_unit(tcx)), } } @@ -480,13 +480,11 @@ fn mul_sorted_consts<'tcx>( b: ty::Const<'tcx>, ) -> Option<ty::Const<'tcx>> { use crate::mir::BinOp::Mul; - use ty::ConstKind::Expr; - use ty::Expr::Binop; let mut work = vec![a, b]; let mut done = vec![]; while let Some(n) = work.pop() { - if let Expr(Binop(Mul, l, r)) = n.kind() { + if let ConstKind::Expr(ty::Expr::Binop(Mul, l, r)) = n.kind() { work.push(l); work.push(r) } else { @@ -517,7 +515,7 @@ fn mul_sorted_consts<'tcx>( done.sort_unstable(); // create a single tree from the buffer - done.into_iter().reduce(|acc, n| tcx.mk_const(Expr(Binop(Mul, n, acc)), n.ty())) + done.into_iter().reduce(|acc, n| ty::Const::new_expr(tcx, ty::Expr::Binop(Mul, n, acc), n.ty())) } pub trait HasTyCtxt<'tcx>: HasDataLayout { @@ -812,11 +810,11 @@ where // (which may have no non-DST form), and will work as long // as the `Abi` or `FieldsShape` is checked by users. if i == 0 { - let nil = tcx.mk_unit(); + let nil = Ty::new_unit(tcx); let unit_ptr_ty = if this.ty.is_unsafe_ptr() { - tcx.mk_mut_ptr(nil) + Ty::new_mut_ptr(tcx, nil) } else { - tcx.mk_mut_ref(tcx.lifetimes.re_static, nil) + Ty::new_mut_ref(tcx, tcx.lifetimes.re_static, nil) }; // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing @@ -829,7 +827,11 @@ where } let mk_dyn_vtable = || { - tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3)) + Ty::new_imm_ref( + tcx, + tcx.lifetimes.re_static, + Ty::new_array(tcx, tcx.types.usize, 3), + ) /* FIXME: use actual fn pointers Warning: naively computing the number of entries in the vtable by counting the methods on the trait + methods on @@ -838,9 +840,9 @@ where Increase this counter if you tried to implement this but failed to do it without duplicating a lot of code from other places in the compiler: 2 - tcx.mk_tup(&[ - tcx.mk_array(tcx.types.usize, 3), - tcx.mk_array(Option<fn()>), + Ty::new_tup(tcx,&[ + Ty::new_array(tcx,tcx.types.usize, 3), + Ty::new_array(tcx,Option<fn()>), ]) */ }; @@ -852,7 +854,7 @@ where { let metadata = tcx.normalize_erasing_regions( cx.param_env(), - tcx.mk_projection(metadata_def_id, [pointee]), + Ty::new_projection(tcx,metadata_def_id, [pointee]), ); // Map `Metadata = DynMetadata<dyn Trait>` back to a vtable, since it @@ -927,15 +929,14 @@ where ty::Dynamic(_, _, ty::DynStar) => { if i == 0 { - TyMaybeWithLayout::Ty(tcx.mk_mut_ptr(tcx.types.unit)) + TyMaybeWithLayout::Ty(Ty::new_mut_ptr(tcx, tcx.types.unit)) } else if i == 1 { // FIXME(dyn-star) same FIXME as above applies here too - TyMaybeWithLayout::Ty( - tcx.mk_imm_ref( - tcx.lifetimes.re_static, - tcx.mk_array(tcx.types.usize, 3), - ), - ) + TyMaybeWithLayout::Ty(Ty::new_imm_ref( + tcx, + tcx.lifetimes.re_static, + Ty::new_array(tcx, tcx.types.usize, 3), + )) } else { bug!("no field {i} on dyn*") } @@ -980,10 +981,8 @@ where }) } ty::FnPtr(fn_sig) if offset.bytes() == 0 => { - tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| PointeeInfo { - size: layout.size, - align: layout.align.abi, - safe: None, + tcx.layout_of(param_env.and(Ty::new_fn_ptr(tcx, fn_sig))).ok().map(|layout| { + PointeeInfo { size: layout.size, align: layout.align.abi, safe: None } }) } ty::Ref(_, ty, mt) if offset.bytes() == 0 => { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 7bd49ad07ea..c100c45b61a 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -66,6 +66,10 @@ use std::{fmt, str}; pub use crate::ty::diagnostics::*; pub use rustc_type_ir::AliasKind::*; +pub use rustc_type_ir::ConstKind::{ + Bound as BoundCt, Error as ErrorCt, Expr as ExprCt, Infer as InferCt, Param as ParamCt, + Placeholder as PlaceholderCt, Unevaluated, Value, +}; pub use rustc_type_ir::DynKind::*; pub use rustc_type_ir::InferTy::*; pub use rustc_type_ir::RegionKind::*; @@ -81,7 +85,7 @@ pub use self::closure::{ CAPTURE_STRUCT_LOCAL, }; pub use self::consts::{ - Const, ConstData, ConstInt, ConstKind, Expr, InferConst, ScalarInt, UnevaluatedConst, ValTree, + Const, ConstData, ConstInt, Expr, InferConst, ScalarInt, UnevaluatedConst, ValTree, }; pub use self::context::{ tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed, @@ -93,7 +97,7 @@ pub use self::rvalue_scopes::RvalueScopes; pub use self::sty::BoundRegionKind::*; pub use self::sty::{ AliasTy, Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, - BoundVariableKind, CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, + BoundVariableKind, CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstKind, ConstVid, EarlyBoundRegion, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig, GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst, ParamTy, PolyExistentialPredicate, @@ -554,8 +558,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::Coerce(_) | PredicateKind::Clause(ClauseKind::ConstEvaluatable(_)) | PredicateKind::ConstEquate(_, _) - | PredicateKind::Ambiguous - | PredicateKind::Clause(ClauseKind::TypeWellFormedFromEnv(_)) => true, + | PredicateKind::Ambiguous => true, } } } @@ -661,11 +664,6 @@ pub enum ClauseKind<'tcx> { /// Constant initializer must evaluate successfully. ConstEvaluatable(ty::Const<'tcx>), - - /// Represents a type found in the environment that we can use for implied bounds. - /// - /// Only used for Chalk. - TypeWellFormedFromEnv(Ty<'tcx>), } #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] @@ -1424,8 +1422,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::Clause(ClauseKind::TypeOutlives(..)) | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) | PredicateKind::ConstEquate(..) - | PredicateKind::Ambiguous - | PredicateKind::Clause(ClauseKind::TypeWellFormedFromEnv(..)) => None, + | PredicateKind::Ambiguous => None, } } @@ -1445,8 +1442,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::Clause(ClauseKind::TypeOutlives(..)) | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) | PredicateKind::ConstEquate(..) - | PredicateKind::Ambiguous - | PredicateKind::Clause(ClauseKind::TypeWellFormedFromEnv(..)) => None, + | PredicateKind::Ambiguous => None, } } @@ -1466,8 +1462,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::ClosureKind(..) | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) | PredicateKind::ConstEquate(..) - | PredicateKind::Ambiguous - | PredicateKind::Clause(ClauseKind::TypeWellFormedFromEnv(..)) => None, + | PredicateKind::Ambiguous => None, } } diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index d1ed7be3d2e..b10921eff08 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -150,17 +150,17 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> { match *ty.kind() { ty::Closure(def_id, substs) => { let substs = self.fold_closure_substs(def_id, substs); - self.tcx.mk_closure(def_id, substs) + Ty::new_closure(self.tcx, def_id, substs) } ty::Generator(def_id, substs, movability) => { let substs = self.fold_closure_substs(def_id, substs); - self.tcx.mk_generator(def_id, substs, movability) + Ty::new_generator(self.tcx, def_id, substs, movability) } ty::GeneratorWitnessMIR(def_id, substs) => { let substs = self.fold_closure_substs(def_id, substs); - self.tcx.mk_generator_witness_mir(def_id, substs) + Ty::new_generator_witness_mir(self.tcx, def_id, substs) } ty::Param(param) => { @@ -186,7 +186,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> { .emit(); } - self.interner().ty_error_misc() + Ty::new_misc_error(self.tcx) } } } @@ -216,7 +216,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> { }) .emit_unless(self.ignore_errors); - self.interner().const_error(ct.ty(), guar) + ty::Const::new_error(self.tcx, guar, ct.ty()) } } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index dcc8247937d..96cf36eb996 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1228,7 +1228,7 @@ pub trait PrettyPrinter<'tcx>: // in order to place the projections inside the `<...>`. if !resugared { // Use a type that can't appear in defaults of type parameters. - let dummy_cx = cx.tcx().mk_fresh_ty(0); + let dummy_cx = Ty::new_fresh(cx.tcx(), 0); let principal = principal.with_self_ty(cx.tcx(), dummy_cx); let args = cx @@ -1393,11 +1393,12 @@ pub trait PrettyPrinter<'tcx>: self, scalar: Scalar, ty: Ty<'tcx>, - print_ty: bool, ) -> Result<Self::Const, Self::Error> { match scalar { - Scalar::Ptr(ptr, _size) => self.pretty_print_const_scalar_ptr(ptr, ty, print_ty), - Scalar::Int(int) => self.pretty_print_const_scalar_int(int, ty, print_ty), + Scalar::Ptr(ptr, _size) => self.pretty_print_const_scalar_ptr(ptr, ty), + Scalar::Int(int) => { + self.pretty_print_const_scalar_int(int, ty, /* print_ty */ true) + } } } @@ -1405,7 +1406,6 @@ pub trait PrettyPrinter<'tcx>: mut self, ptr: Pointer, ty: Ty<'tcx>, - print_ty: bool, ) -> Result<Self::Const, Self::Error> { define_scoped_cx!(self); @@ -1459,7 +1459,7 @@ pub trait PrettyPrinter<'tcx>: _ => {} } // Any pointer values not covered by a branch above - self = self.pretty_print_const_pointer(ptr, ty, print_ty)?; + self = self.pretty_print_const_pointer(ptr, ty)?; Ok(self) } @@ -1527,24 +1527,18 @@ pub trait PrettyPrinter<'tcx>: /// This is overridden for MIR printing because we only want to hide alloc ids from users, not /// from MIR where it is actually useful. fn pretty_print_const_pointer<Prov: Provenance>( - mut self, + self, _: Pointer<Prov>, ty: Ty<'tcx>, - print_ty: bool, ) -> Result<Self::Const, Self::Error> { - if print_ty { - self.typed_value( - |mut this| { - this.write_str("&_")?; - Ok(this) - }, - |this| this.print_type(ty), - ": ", - ) - } else { - self.write_str("&_")?; - Ok(self) - } + self.typed_value( + |mut this| { + this.write_str("&_")?; + Ok(this) + }, + |this| this.print_type(ty), + ": ", + ) } fn pretty_print_byte_str(mut self, byte_str: &'tcx [u8]) -> Result<Self::Const, Self::Error> { @@ -1601,7 +1595,8 @@ pub trait PrettyPrinter<'tcx>: } // Aggregates, printed as array/tuple/struct/variant construction syntax. (ty::ValTree::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => { - let contents = self.tcx().destructure_const(self.tcx().mk_const(valtree, ty)); + let contents = + self.tcx().destructure_const(ty::Const::new_value(self.tcx(), valtree, ty)); let fields = contents.fields.iter().copied(); match *ty.kind() { ty::Array(..) => { @@ -2155,7 +2150,6 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { self, p: Pointer<Prov>, ty: Ty<'tcx>, - print_ty: bool, ) -> Result<Self::Const, Self::Error> { let print = |mut this: Self| { define_scoped_cx!(this); @@ -2166,11 +2160,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { } Ok(this) }; - if print_ty { - self.typed_value(print, |this| this.print_type(ty), ": ") - } else { - print(self) - } + self.typed_value(print, |this| this.print_type(ty), ": ") } } @@ -2746,7 +2736,7 @@ define_print_and_forward_display! { ty::ExistentialTraitRef<'tcx> { // Use a type that can't appear in defaults of type parameters. - let dummy_self = cx.tcx().mk_fresh_ty(0); + let dummy_self = Ty::new_fresh(cx.tcx(),0); let trait_ref = self.with_self_ty(cx.tcx(), dummy_self); p!(print(trait_ref.print_only_trait_path())) } @@ -2888,9 +2878,6 @@ define_print_and_forward_display! { ty::ClauseKind::ConstEvaluatable(ct) => { p!("the constant `", print(ct), "` can be evaluated") } - ty::ClauseKind::TypeWellFormedFromEnv(ty) => { - p!("the type `", print(ty), "` is found in the environment") - } } } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 74a3bddf2fa..5741832c980 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -408,7 +408,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( bug!("bound types encountered in structurally_relate_tys") } - (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(tcx.ty_error(guar)), + (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(tcx, guar)), (&ty::Never, _) | (&ty::Char, _) @@ -428,10 +428,10 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs)) if a_def == b_def => { let substs = relation.relate_item_substs(a_def.did(), a_substs, b_substs)?; - Ok(tcx.mk_adt(a_def, substs)) + Ok(Ty::new_adt(tcx, a_def, substs)) } - (&ty::Foreign(a_id), &ty::Foreign(b_id)) if a_id == b_id => Ok(tcx.mk_foreign(a_id)), + (&ty::Foreign(a_id), &ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(tcx, a_id)), (&ty::Dynamic(a_obj, a_region, a_repr), &ty::Dynamic(b_obj, b_region, b_repr)) if a_repr == b_repr => @@ -439,7 +439,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| { relation.relate(a_region, b_region) })?; - Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound, a_repr)) + Ok(Ty::new_dynamic(tcx, relation.relate(a_obj, b_obj)?, region_bound, a_repr)) } (&ty::Generator(a_id, a_substs, movability), &ty::Generator(b_id, b_substs, _)) @@ -449,7 +449,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( // the (anonymous) type of the same generator expression. So // all of their regions should be equated. let substs = relation.relate(a_substs, b_substs)?; - Ok(tcx.mk_generator(a_id, substs, movability)) + Ok(Ty::new_generator(tcx, a_id, substs, movability)) } (&ty::GeneratorWitness(a_types), &ty::GeneratorWitness(b_types)) => { @@ -459,7 +459,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( let b_types = b_types.map_bound(GeneratorWitness); // Then remove the GeneratorWitness for the result let types = relation.relate(a_types, b_types)?.map_bound(|witness| witness.0); - Ok(tcx.mk_generator_witness(types)) + Ok(Ty::new_generator_witness(tcx, types)) } (&ty::GeneratorWitnessMIR(a_id, a_substs), &ty::GeneratorWitnessMIR(b_id, b_substs)) @@ -469,7 +469,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( // the (anonymous) type of the same generator expression. So // all of their regions should be equated. let substs = relation.relate(a_substs, b_substs)?; - Ok(tcx.mk_generator_witness_mir(a_id, substs)) + Ok(Ty::new_generator_witness_mir(tcx, a_id, substs)) } (&ty::Closure(a_id, a_substs), &ty::Closure(b_id, b_substs)) if a_id == b_id => { @@ -477,12 +477,12 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( // the (anonymous) type of the same closure expression. So // all of their regions should be equated. let substs = relation.relate(a_substs, b_substs)?; - Ok(tcx.mk_closure(a_id, &substs)) + Ok(Ty::new_closure(tcx, a_id, &substs)) } (&ty::RawPtr(a_mt), &ty::RawPtr(b_mt)) => { let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?; - Ok(tcx.mk_ptr(mt)) + Ok(Ty::new_ptr(tcx, mt)) } (&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => { @@ -490,13 +490,13 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl }; let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl }; let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?; - Ok(tcx.mk_ref(r, mt)) + Ok(Ty::new_ref(tcx, r, mt)) } (&ty::Array(a_t, sz_a), &ty::Array(b_t, sz_b)) => { let t = relation.relate(a_t, b_t)?; match relation.relate(sz_a, sz_b) { - Ok(sz) => Ok(tcx.mk_array_with_const_len(t, sz)), + Ok(sz) => Ok(Ty::new_array_with_const_len(tcx, t, sz)), Err(err) => { // Check whether the lengths are both concrete/known values, // but are unequal, for better diagnostics. @@ -519,12 +519,15 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( (&ty::Slice(a_t), &ty::Slice(b_t)) => { let t = relation.relate(a_t, b_t)?; - Ok(tcx.mk_slice(t)) + Ok(Ty::new_slice(tcx, t)) } (&ty::Tuple(as_), &ty::Tuple(bs)) => { if as_.len() == bs.len() { - Ok(tcx.mk_tup_from_iter(iter::zip(as_, bs).map(|(a, b)| relation.relate(a, b)))?) + Ok(Ty::new_tup_from_iter( + tcx, + iter::zip(as_, bs).map(|(a, b)| relation.relate(a, b)), + )?) } else if !(as_.is_empty() || bs.is_empty()) { Err(TypeError::TupleSize(expected_found(relation, as_.len(), bs.len()))) } else { @@ -536,25 +539,16 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( if a_def_id == b_def_id => { let substs = relation.relate_item_substs(a_def_id, a_substs, b_substs)?; - Ok(tcx.mk_fn_def(a_def_id, substs)) + Ok(Ty::new_fn_def(tcx, a_def_id, substs)) } (&ty::FnPtr(a_fty), &ty::FnPtr(b_fty)) => { let fty = relation.relate(a_fty, b_fty)?; - Ok(tcx.mk_fn_ptr(fty)) - } - - // these two are already handled downstream in case of lazy normalization - (&ty::Alias(ty::Projection, a_data), &ty::Alias(ty::Projection, b_data)) => { - let projection_ty = relation.relate(a_data, b_data)?; - Ok(tcx.mk_projection(projection_ty.def_id, projection_ty.substs)) - } - - (&ty::Alias(ty::Inherent, a_data), &ty::Alias(ty::Inherent, b_data)) => { - let alias_ty = relation.relate(a_data, b_data)?; - Ok(tcx.mk_alias(ty::Inherent, tcx.mk_alias_ty(alias_ty.def_id, alias_ty.substs))) + Ok(Ty::new_fn_ptr(tcx, fty)) } + // The substs of opaque types may not all be invariant, so we have + // to treat them separately from other aliases. ( &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: a_substs, .. }), &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: b_substs, .. }), @@ -568,7 +562,20 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( b_substs, false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle )?; - Ok(tcx.mk_opaque(a_def_id, substs)) + Ok(Ty::new_opaque(tcx, a_def_id, substs)) + } + + // Alias tend to mostly already be handled downstream due to normalization. + (&ty::Alias(a_kind, a_data), &ty::Alias(b_kind, b_data)) => { + // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): This if can be removed + // and the assert uncommented once the new desugaring is stable. + if a_kind == b_kind { + let alias_ty = relation.relate(a_data, b_data)?; + // assert_eq!(a_kind, b_kind); + Ok(Ty::new_alias(tcx, a_kind, alias_ty)) + } else { + Err(TypeError::Sorts(expected_found(relation, a, b))) + } } _ => Err(TypeError::Sorts(expected_found(relation, a, b))), @@ -623,7 +630,11 @@ pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>( au.substs, bu.substs, )?; - return Ok(tcx.mk_const(ty::UnevaluatedConst { def: au.def, substs }, a.ty())); + return Ok(ty::Const::new_unevaluated( + tcx, + ty::UnevaluatedConst { def: au.def, substs }, + a.ty(), + )); } // Before calling relate on exprs, it is necessary to ensure that the nested consts // have identical types. @@ -664,8 +675,7 @@ pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>( } _ => return Err(TypeError::ConstMismatch(expected_found(r, a, b))), }; - let kind = ty::ConstKind::Expr(expr); - return Ok(tcx.mk_const(kind, a.ty())); + return Ok(ty::Const::new_expr(tcx, expr, a.ty())); } _ => false, }; diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 113328de176..4a639a2a0fe 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -11,6 +11,7 @@ use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; use rustc_hir::def::Namespace; use rustc_index::{Idx, IndexVec}; use rustc_target::abi::TyAndLayout; +use rustc_type_ir::ConstKind; use std::fmt; use std::ops::ControlFlow; @@ -189,9 +190,6 @@ impl<'tcx> fmt::Debug for ty::ClauseKind<'tcx> { ty::ClauseKind::ConstEvaluatable(ct) => { write!(f, "ConstEvaluatable({ct:?})") } - ty::ClauseKind::TypeWellFormedFromEnv(ty) => { - write!(f, "TypeWellFormedFromEnv({:?})", ty) - } } } } @@ -244,24 +242,6 @@ impl<'tcx> fmt::Debug for ty::Const<'tcx> { } } -impl<'tcx> fmt::Debug for ty::ConstKind<'tcx> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - use ty::ConstKind::*; - match self { - Param(param) => write!(f, "{param:?}"), - Infer(var) => write!(f, "{var:?}"), - Bound(debruijn, var) => rustc_type_ir::debug_bound_var(f, *debruijn, *var), - Placeholder(placeholder) => write!(f, "{placeholder:?}"), - Unevaluated(uv) => { - f.debug_tuple("Unevaluated").field(&uv.substs).field(&uv.def).finish() - } - Value(valtree) => write!(f, "{valtree:?}"), - Error(_) => write!(f, "{{const error}}"), - Expr(expr) => write!(f, "{expr:?}"), - } - } -} - impl fmt::Debug for ty::BoundTy { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.kind { @@ -731,9 +711,20 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> { folder: &mut F, ) -> Result<Self, F::Error> { let ty = self.ty().try_fold_with(folder)?; - let kind = self.kind().try_fold_with(folder)?; + let kind = match self.kind() { + ConstKind::Param(p) => ConstKind::Param(p.try_fold_with(folder)?), + ConstKind::Infer(i) => ConstKind::Infer(i.try_fold_with(folder)?), + ConstKind::Bound(d, b) => { + ConstKind::Bound(d.try_fold_with(folder)?, b.try_fold_with(folder)?) + } + ConstKind::Placeholder(p) => ConstKind::Placeholder(p.try_fold_with(folder)?), + ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.try_fold_with(folder)?), + ConstKind::Value(v) => ConstKind::Value(v.try_fold_with(folder)?), + ConstKind::Error(e) => ConstKind::Error(e.try_fold_with(folder)?), + ConstKind::Expr(e) => ConstKind::Expr(e.try_fold_with(folder)?), + }; if ty != self.ty() || kind != self.kind() { - Ok(folder.interner().mk_const(kind, ty)) + Ok(folder.interner().mk_ct_from_kind(kind, ty)) } else { Ok(self) } @@ -746,7 +737,19 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> { visitor: &mut V, ) -> ControlFlow<V::BreakTy> { self.ty().visit_with(visitor)?; - self.kind().visit_with(visitor) + match self.kind() { + ConstKind::Param(p) => p.visit_with(visitor), + ConstKind::Infer(i) => i.visit_with(visitor), + ConstKind::Bound(d, b) => { + d.visit_with(visitor)?; + b.visit_with(visitor) + } + ConstKind::Placeholder(p) => p.visit_with(visitor), + ConstKind::Unevaluated(uv) => uv.visit_with(visitor), + ConstKind::Value(v) => v.visit_with(visitor), + ConstKind::Error(e) => e.visit_with(visitor), + ConstKind::Expr(e) => e.visit_with(visitor), + } } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index bb6d49e1773..94746fbdc19 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -15,6 +15,7 @@ use hir::def::DefKind; use polonius_engine::Atom; use rustc_data_structures::captures::Captures; use rustc_data_structures::intern::Interned; +use rustc_error_messages::DiagnosticMessage; use rustc_errors::{DiagnosticArgValue, ErrorGuaranteed, IntoDiagnosticArg, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -25,6 +26,7 @@ use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; use rustc_target::spec::abi::{self, Abi}; +use std::assert_matches::debug_assert_matches; use std::borrow::Cow; use std::cmp::Ordering; use std::fmt; @@ -33,13 +35,17 @@ use std::ops::{ControlFlow, Deref, Range}; use ty::util::IntTypeExt; use rustc_type_ir::sty::TyKind::*; -use rustc_type_ir::RegionKind as IrRegionKind; use rustc_type_ir::TyKind as IrTyKind; +use rustc_type_ir::{CollectAndApply, ConstKind as IrConstKind}; +use rustc_type_ir::{DynKind, RegionKind as IrRegionKind}; + +use super::GenericParamDefKind; // Re-export the `TyKind` from `rustc_type_ir` here for convenience #[rustc_diagnostic_item = "TyKind"] pub type TyKind<'tcx> = IrTyKind<TyCtxt<'tcx>>; pub type RegionKind<'tcx> = IrRegionKind<TyCtxt<'tcx>>; +pub type ConstKind<'tcx> = IrConstKind<TyCtxt<'tcx>>; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] @@ -1239,7 +1245,7 @@ impl<'tcx> AliasTy<'tcx> { } pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - tcx.mk_alias(self.kind(tcx), self) + Ty::new_alias(tcx, self.kind(tcx), self) } } @@ -1430,7 +1436,7 @@ impl<'tcx> ParamTy { #[inline] pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - tcx.mk_ty_param(self.index, self.name) + Ty::new_param(tcx, self.index, self.name) } pub fn span_from_generics(&self, tcx: TyCtxt<'tcx>, item_with_generics: DefId) -> Span { @@ -1871,6 +1877,390 @@ impl<'tcx> Region<'tcx> { } } +/// Constructors for `Ty` +impl<'tcx> Ty<'tcx> { + // Avoid this in favour of more specific `new_*` methods, where possible. + #[allow(rustc::usage_of_ty_tykind)] + #[inline] + pub fn new(tcx: TyCtxt<'tcx>, st: TyKind<'tcx>) -> Ty<'tcx> { + tcx.mk_ty_from_kind(st) + } + + #[inline] + pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferTy) -> Ty<'tcx> { + Ty::new(tcx, TyKind::Infer(infer)) + } + + #[inline] + pub fn new_var(tcx: TyCtxt<'tcx>, v: ty::TyVid) -> Ty<'tcx> { + // Use a pre-interned one when possible. + tcx.types + .ty_vars + .get(v.as_usize()) + .copied() + .unwrap_or_else(|| Ty::new(tcx, Infer(TyVar(v)))) + } + + #[inline] + pub fn new_int_var(tcx: TyCtxt<'tcx>, v: ty::IntVid) -> Ty<'tcx> { + Ty::new_infer(tcx, IntVar(v)) + } + + #[inline] + pub fn new_float_var(tcx: TyCtxt<'tcx>, v: ty::FloatVid) -> Ty<'tcx> { + Ty::new_infer(tcx, FloatVar(v)) + } + + #[inline] + pub fn new_fresh(tcx: TyCtxt<'tcx>, n: u32) -> Ty<'tcx> { + // Use a pre-interned one when possible. + tcx.types + .fresh_tys + .get(n as usize) + .copied() + .unwrap_or_else(|| Ty::new_infer(tcx, ty::FreshTy(n))) + } + + #[inline] + pub fn new_fresh_int(tcx: TyCtxt<'tcx>, n: u32) -> Ty<'tcx> { + // Use a pre-interned one when possible. + tcx.types + .fresh_int_tys + .get(n as usize) + .copied() + .unwrap_or_else(|| Ty::new_infer(tcx, ty::FreshIntTy(n))) + } + + #[inline] + pub fn new_fresh_float(tcx: TyCtxt<'tcx>, n: u32) -> Ty<'tcx> { + // Use a pre-interned one when possible. + tcx.types + .fresh_float_tys + .get(n as usize) + .copied() + .unwrap_or_else(|| Ty::new_infer(tcx, ty::FreshFloatTy(n))) + } + + #[inline] + pub fn new_param(tcx: TyCtxt<'tcx>, index: u32, name: Symbol) -> Ty<'tcx> { + tcx.mk_ty_from_kind(Param(ParamTy { index, name })) + } + + #[inline] + pub fn new_bound( + tcx: TyCtxt<'tcx>, + index: ty::DebruijnIndex, + bound_ty: ty::BoundTy, + ) -> Ty<'tcx> { + Ty::new(tcx, Bound(index, bound_ty)) + } + + #[inline] + pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderType) -> Ty<'tcx> { + Ty::new(tcx, Placeholder(placeholder)) + } + + #[inline] + pub fn new_alias( + tcx: TyCtxt<'tcx>, + kind: ty::AliasKind, + alias_ty: ty::AliasTy<'tcx>, + ) -> Ty<'tcx> { + debug_assert_matches!( + (kind, tcx.def_kind(alias_ty.def_id)), + (ty::Opaque, DefKind::OpaqueTy) + | (ty::Projection | ty::Inherent, DefKind::AssocTy) + | (ty::Opaque | ty::Projection, DefKind::ImplTraitPlaceholder) + | (ty::Weak, DefKind::TyAlias) + ); + Ty::new(tcx, Alias(kind, alias_ty)) + } + + #[inline] + pub fn new_opaque(tcx: TyCtxt<'tcx>, def_id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> { + Ty::new_alias(tcx, ty::Opaque, tcx.mk_alias_ty(def_id, substs)) + } + + /// Constructs a `TyKind::Error` type with current `ErrorGuaranteed` + pub fn new_error(tcx: TyCtxt<'tcx>, reported: ErrorGuaranteed) -> Ty<'tcx> { + Ty::new(tcx, Error(reported)) + } + + /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used. + #[track_caller] + pub fn new_misc_error(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + Ty::new_error_with_message(tcx, DUMMY_SP, "TyKind::Error constructed but no error reported") + } + + /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to + /// ensure it gets used. + #[track_caller] + pub fn new_error_with_message<S: Into<MultiSpan>>( + tcx: TyCtxt<'tcx>, + span: S, + msg: impl Into<DiagnosticMessage>, + ) -> Ty<'tcx> { + let reported = tcx.sess.delay_span_bug(span, msg); + Ty::new(tcx, Error(reported)) + } + + #[inline] + pub fn new_int(tcx: TyCtxt<'tcx>, i: ty::IntTy) -> Ty<'tcx> { + use ty::IntTy::*; + match i { + Isize => tcx.types.isize, + I8 => tcx.types.i8, + I16 => tcx.types.i16, + I32 => tcx.types.i32, + I64 => tcx.types.i64, + I128 => tcx.types.i128, + } + } + + #[inline] + pub fn new_uint(tcx: TyCtxt<'tcx>, ui: ty::UintTy) -> Ty<'tcx> { + use ty::UintTy::*; + match ui { + Usize => tcx.types.usize, + U8 => tcx.types.u8, + U16 => tcx.types.u16, + U32 => tcx.types.u32, + U64 => tcx.types.u64, + U128 => tcx.types.u128, + } + } + + #[inline] + pub fn new_float(tcx: TyCtxt<'tcx>, f: ty::FloatTy) -> Ty<'tcx> { + use ty::FloatTy::*; + match f { + F32 => tcx.types.f32, + F64 => tcx.types.f64, + } + } + + #[inline] + pub fn new_ref(tcx: TyCtxt<'tcx>, r: Region<'tcx>, tm: TypeAndMut<'tcx>) -> Ty<'tcx> { + Ty::new(tcx, Ref(r, tm.ty, tm.mutbl)) + } + + #[inline] + pub fn new_mut_ref(tcx: TyCtxt<'tcx>, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { + Ty::new_ref(tcx, r, TypeAndMut { ty, mutbl: hir::Mutability::Mut }) + } + + #[inline] + pub fn new_imm_ref(tcx: TyCtxt<'tcx>, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { + Ty::new_ref(tcx, r, TypeAndMut { ty, mutbl: hir::Mutability::Not }) + } + + #[inline] + pub fn new_ptr(tcx: TyCtxt<'tcx>, tm: TypeAndMut<'tcx>) -> Ty<'tcx> { + Ty::new(tcx, RawPtr(tm)) + } + + #[inline] + pub fn new_mut_ptr(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { + Ty::new_ptr(tcx, TypeAndMut { ty, mutbl: hir::Mutability::Mut }) + } + + #[inline] + pub fn new_imm_ptr(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { + Ty::new_ptr(tcx, TypeAndMut { ty, mutbl: hir::Mutability::Not }) + } + + #[inline] + pub fn new_adt(tcx: TyCtxt<'tcx>, def: AdtDef<'tcx>, substs: SubstsRef<'tcx>) -> Ty<'tcx> { + Ty::new(tcx, Adt(def, substs)) + } + + #[inline] + pub fn new_foreign(tcx: TyCtxt<'tcx>, def_id: DefId) -> Ty<'tcx> { + Ty::new(tcx, Foreign(def_id)) + } + + #[inline] + pub fn new_array(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> { + Ty::new(tcx, Array(ty, ty::Const::from_target_usize(tcx, n))) + } + + #[inline] + pub fn new_array_with_const_len( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + ct: ty::Const<'tcx>, + ) -> Ty<'tcx> { + Ty::new(tcx, Array(ty, ct)) + } + + #[inline] + pub fn new_slice(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { + Ty::new(tcx, Slice(ty)) + } + + #[inline] + pub fn new_tup(tcx: TyCtxt<'tcx>, ts: &[Ty<'tcx>]) -> Ty<'tcx> { + if ts.is_empty() { tcx.types.unit } else { Ty::new(tcx, Tuple(tcx.mk_type_list(&ts))) } + } + + pub fn new_tup_from_iter<I, T>(tcx: TyCtxt<'tcx>, iter: I) -> T::Output + where + I: Iterator<Item = T>, + T: CollectAndApply<Ty<'tcx>, Ty<'tcx>>, + { + T::collect_and_apply(iter, |ts| Ty::new_tup(tcx, ts)) + } + + #[inline] + pub fn new_fn_def( + tcx: TyCtxt<'tcx>, + def_id: DefId, + substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>, + ) -> Ty<'tcx> { + let substs = tcx.check_and_mk_substs(def_id, substs); + Ty::new(tcx, FnDef(def_id, substs)) + } + + #[inline] + pub fn new_fn_ptr(tcx: TyCtxt<'tcx>, fty: PolyFnSig<'tcx>) -> Ty<'tcx> { + Ty::new(tcx, FnPtr(fty)) + } + + #[inline] + pub fn new_dynamic( + tcx: TyCtxt<'tcx>, + obj: &'tcx List<PolyExistentialPredicate<'tcx>>, + reg: ty::Region<'tcx>, + repr: DynKind, + ) -> Ty<'tcx> { + Ty::new(tcx, Dynamic(obj, reg, repr)) + } + + #[inline] + pub fn new_projection( + tcx: TyCtxt<'tcx>, + item_def_id: DefId, + substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>, + ) -> Ty<'tcx> { + Ty::new_alias(tcx, ty::Projection, tcx.mk_alias_ty(item_def_id, substs)) + } + + #[inline] + pub fn new_closure( + tcx: TyCtxt<'tcx>, + def_id: DefId, + closure_substs: SubstsRef<'tcx>, + ) -> Ty<'tcx> { + debug_assert_eq!( + closure_substs.len(), + tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 3, + "closure constructed with incorrect substitutions" + ); + Ty::new(tcx, Closure(def_id, closure_substs)) + } + + #[inline] + pub fn new_generator( + tcx: TyCtxt<'tcx>, + def_id: DefId, + generator_substs: SubstsRef<'tcx>, + movability: hir::Movability, + ) -> Ty<'tcx> { + debug_assert_eq!( + generator_substs.len(), + tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 5, + "generator constructed with incorrect number of substitutions" + ); + Ty::new(tcx, Generator(def_id, generator_substs, movability)) + } + + #[inline] + pub fn new_generator_witness( + tcx: TyCtxt<'tcx>, + types: ty::Binder<'tcx, &'tcx List<Ty<'tcx>>>, + ) -> Ty<'tcx> { + Ty::new(tcx, GeneratorWitness(types)) + } + + #[inline] + pub fn new_generator_witness_mir( + tcx: TyCtxt<'tcx>, + id: DefId, + substs: SubstsRef<'tcx>, + ) -> Ty<'tcx> { + Ty::new(tcx, GeneratorWitnessMIR(id, substs)) + } + + // misc + + #[inline] + pub fn new_unit(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + tcx.types.unit + } + + #[inline] + pub fn new_static_str(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, tcx.types.str_) + } + + #[inline] + pub fn new_diverging_default(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + if tcx.features().never_type_fallback { tcx.types.never } else { tcx.types.unit } + } + + // lang and diagnostic tys + + fn new_generic_adt(tcx: TyCtxt<'tcx>, wrapper_def_id: DefId, ty_param: Ty<'tcx>) -> Ty<'tcx> { + let adt_def = tcx.adt_def(wrapper_def_id); + let substs = + InternalSubsts::for_item(tcx, wrapper_def_id, |param, substs| match param.kind { + GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => bug!(), + GenericParamDefKind::Type { has_default, .. } => { + if param.index == 0 { + ty_param.into() + } else { + assert!(has_default); + tcx.type_of(param.def_id).subst(tcx, substs).into() + } + } + }); + Ty::new(tcx, Adt(adt_def, substs)) + } + + #[inline] + pub fn new_lang_item(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, item: LangItem) -> Option<Ty<'tcx>> { + let def_id = tcx.lang_items().get(item)?; + Some(Ty::new_generic_adt(tcx, def_id, ty)) + } + + #[inline] + pub fn new_diagnostic_item(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, name: Symbol) -> Option<Ty<'tcx>> { + let def_id = tcx.get_diagnostic_item(name)?; + Some(Ty::new_generic_adt(tcx, def_id, ty)) + } + + #[inline] + pub fn new_box(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { + let def_id = tcx.require_lang_item(LangItem::OwnedBox, None); + Ty::new_generic_adt(tcx, def_id, ty) + } + + #[inline] + pub fn new_maybe_uninit(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { + let def_id = tcx.require_lang_item(LangItem::MaybeUninit, None); + Ty::new_generic_adt(tcx, def_id, ty) + } + + /// Creates a `&mut Context<'_>` [`Ty`] with erased lifetimes. + pub fn new_task_context(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + let context_did = tcx.require_lang_item(LangItem::Context, None); + let context_adt_ref = tcx.adt_def(context_did); + let context_substs = tcx.mk_substs(&[tcx.lifetimes.re_erased.into()]); + let context_ty = Ty::new_adt(tcx, context_adt_ref, context_substs); + Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, context_ty) + } +} + /// Type utilities impl<'tcx> Ty<'tcx> { #[inline(always)] @@ -2314,7 +2704,7 @@ impl<'tcx> Ty<'tcx> { let assoc_items = tcx.associated_item_def_ids( tcx.require_lang_item(hir::LangItem::DiscriminantKind, None), ); - tcx.mk_projection(assoc_items[0], tcx.mk_substs(&[self.into()])) + Ty::new_projection(tcx, assoc_items[0], tcx.mk_substs(&[self.into()])) } ty::Bool diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 111b1d009b3..4d5f5b8658c 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -11,6 +11,7 @@ use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_serialize::{self, Decodable, Encodable}; +use rustc_span::sym; use rustc_type_ir::WithCachedTypeInfo; use smallvec::SmallVec; @@ -451,6 +452,10 @@ impl<'tcx> InternalSubsts<'tcx> { pub fn truncate_to(&self, tcx: TyCtxt<'tcx>, generics: &ty::Generics) -> SubstsRef<'tcx> { tcx.mk_substs_from_iter(self.iter().take(generics.count())) } + + pub fn host_effect_param(&'tcx self) -> Option<ty::Const<'tcx>> { + self.consts().rfind(|x| matches!(x.kind(), ty::ConstKind::Param(p) if p.name == sym::host)) + } } impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for SubstsRef<'tcx> { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index bb08deff294..720d770eed4 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -223,7 +223,7 @@ impl<'tcx> TyCtxt<'tcx> { }; let reported = self.sess.emit_err(crate::error::RecursionLimitReached { ty, suggested_limit }); - return self.ty_error(reported); + return Ty::new_error(self, reported); } match *ty.kind() { ty::Adt(def, substs) => { @@ -610,12 +610,12 @@ impl<'tcx> TyCtxt<'tcx> { closure_substs: SubstsRef<'tcx>, env_region: ty::Region<'tcx>, ) -> Option<Ty<'tcx>> { - let closure_ty = self.mk_closure(closure_def_id, closure_substs); + let closure_ty = Ty::new_closure(self, closure_def_id, closure_substs); let closure_kind_ty = closure_substs.as_closure().kind_ty(); let closure_kind = closure_kind_ty.to_opt_closure_kind()?; let env_ty = match closure_kind { - ty::ClosureKind::Fn => self.mk_imm_ref(env_region, closure_ty), - ty::ClosureKind::FnMut => self.mk_mut_ref(env_region, closure_ty), + ty::ClosureKind::Fn => Ty::new_imm_ref(self, env_region, closure_ty), + ty::ClosureKind::FnMut => Ty::new_mut_ref(self, env_region, closure_ty), ty::ClosureKind::FnOnce => closure_ty, }; Some(env_ty) @@ -656,12 +656,12 @@ impl<'tcx> TyCtxt<'tcx> { pub fn thread_local_ptr_ty(self, def_id: DefId) -> Ty<'tcx> { let static_ty = self.type_of(def_id).subst_identity(); if self.is_mutable_static(def_id) { - self.mk_mut_ptr(static_ty) + Ty::new_mut_ptr(self, static_ty) } else if self.is_foreign_item(def_id) { - self.mk_imm_ptr(static_ty) + Ty::new_imm_ptr(self, static_ty) } else { // FIXME: These things don't *really* have 'static lifetime. - self.mk_imm_ref(self.lifetimes.re_static, static_ty) + Ty::new_imm_ref(self, self.lifetimes.re_static, static_ty) } } @@ -676,11 +676,11 @@ impl<'tcx> TyCtxt<'tcx> { // Make sure that accesses to unsafe statics end up using raw pointers. // For thread-locals, this needs to be kept in sync with `Rvalue::ty`. if self.is_mutable_static(def_id) { - self.mk_mut_ptr(static_ty) + Ty::new_mut_ptr(self, static_ty) } else if self.is_foreign_item(def_id) { - self.mk_imm_ptr(static_ty) + Ty::new_imm_ptr(self, static_ty) } else { - self.mk_imm_ref(self.lifetimes.re_erased, static_ty) + Ty::new_imm_ref(self, self.lifetimes.re_erased, static_ty) } } @@ -854,7 +854,7 @@ impl<'tcx> OpaqueTypeExpander<'tcx> { let hidden_ty = bty.subst(self.tcx, substs); self.fold_ty(hidden_ty); } - let expanded_ty = self.tcx.mk_generator_witness_mir(def_id, substs); + let expanded_ty = Ty::new_generator_witness_mir(self.tcx, def_id, substs); self.expanded_cache.insert((def_id, substs), expanded_ty); expanded_ty } @@ -1306,7 +1306,7 @@ pub fn needs_drop_components<'tcx>( ty::Array(elem_ty, size) => { match needs_drop_components(*elem_ty, target_layout) { Ok(v) if v.is_empty() => Ok(v), - res => match size.kind().try_to_bits(target_layout.pointer_size) { + res => match size.try_to_bits(target_layout.pointer_size) { // Arrays of size zero don't need drop, even if their element // type does. Some(0) => Ok(SmallVec::new()), diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 8758cd04d67..b0961d91787 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -16,7 +16,7 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Ty<'_> { fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo<DepKind>]) -> Self { // SAFETY: This is never called when `Self` is not `Ty<'tcx>`. // FIXME: Represent the above fact in the trait system somehow. - unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(tcx.ty_error_misc()) } + unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(Ty::new_misc_error(tcx)) } } } @@ -34,7 +34,7 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> { impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::Binder<'_, ty::FnSig<'_>> { fn from_cycle_error(tcx: TyCtxt<'tcx>, stack: &[QueryInfo<DepKind>]) -> Self { - let err = tcx.ty_error_misc(); + let err = Ty::new_misc_error(tcx); let arity = if let Some(frame) = stack.get(0) && frame.query.dep_kind == DepKind::fn_sig diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 73d5eb62750..3fe751ae0a5 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -52,7 +52,7 @@ pub fn as_constant_inner<'tcx>( match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) { Ok(c) => c, Err(LitToConstError::Reported(guar)) => { - ConstantKind::Ty(tcx.const_error(ty, guar)) + ConstantKind::Ty(ty::Const::new_error(tcx, guar, ty)) } Err(LitToConstError::TypeError) => { bug!("encountered type error in `lit_to_mir_constant`") @@ -84,7 +84,7 @@ pub fn as_constant_inner<'tcx>( Constant { user_ty, span, literal } } ExprKind::ConstParam { param, def_id: _ } => { - let const_param = tcx.mk_const(ty::ConstKind::Param(param), expr.ty); + let const_param = ty::Const::new_param(tcx, param, expr.ty); let literal = ConstantKind::Ty(const_param); Constant { user_ty: None, span, literal } diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 783f6e2085c..ac2d099be50 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -683,7 +683,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ProjectionElem::Deref => { let fake_borrow_deref_ty = base_place.ty(&self.local_decls, tcx).ty; let fake_borrow_ty = - tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty); + Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, fake_borrow_deref_ty); let fake_borrow_temp = self.local_decls.push(LocalDecl::new(fake_borrow_ty, expr_span)); let projection = tcx.mk_place_elems(&base_place.projection); diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 27b1b58d2e9..5c886ac4d9b 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -162,7 +162,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { [], expr_span, ); - let storage = this.temp(tcx.mk_mut_ptr(tcx.types.u8), expr_span); + let storage = this.temp(Ty::new_mut_ptr(tcx, tcx.types.u8), expr_span); let success = this.cfg.start_new_block(); this.cfg.terminate( block, @@ -564,7 +564,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let bool_ty = self.tcx.types.bool; let rvalue = match op { BinOp::Add | BinOp::Sub | BinOp::Mul if self.check_overflow && ty.is_integral() => { - let result_tup = self.tcx.mk_tup(&[ty, bool_ty]); + let result_tup = Ty::new_tup(self.tcx, &[ty, bool_ty]); let result_value = self.temp(result_tup, span); self.cfg.push_assign( @@ -598,7 +598,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let (unsigned_rhs, unsigned_ty) = match rhs_ty.kind() { ty::Uint(_) => (rhs.to_copy(), rhs_ty), ty::Int(int_width) => { - let uint_ty = self.tcx.mk_mach_uint(int_width.to_unsigned()); + let uint_ty = Ty::new_uint(self.tcx, int_width.to_unsigned()); let rhs_temp = self.temp(uint_ty, span); self.cfg.push_assign( block, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 6df06df5c60..10770213c9a 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1751,7 +1751,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { projection: tcx.mk_place_elems(matched_place_ref.projection), }; let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty; - let fake_borrow_ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty); + let fake_borrow_ty = + Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, fake_borrow_deref_ty); let mut fake_borrow_temp = LocalDecl::new(fake_borrow_ty, temp_span); fake_borrow_temp.internal = self.local_decls[matched_place.local].internal; fake_borrow_temp.local_info = ClearCrossCrate::Set(Box::new(LocalInfo::FakeBorrow)); @@ -2250,7 +2251,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // This variable isn't mutated but has a name, so has to be // immutable to avoid the unused mut lint. mutability: Mutability::Not, - ty: tcx.mk_imm_ref(tcx.lifetimes.re_erased, var_ty), + ty: Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, var_ty), user_ty: None, source_info, internal: false, diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index f431023f2b6..3a2c506bb98 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -244,8 +244,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { bug!("matching on `String` went through without enabling string_deref_patterns"); } let re_erased = tcx.lifetimes.re_erased; - let ref_string = self.temp(tcx.mk_imm_ref(re_erased, ty), test.span); - let ref_str_ty = tcx.mk_imm_ref(re_erased, tcx.types.str_); + let ref_string = self.temp(Ty::new_imm_ref(tcx,re_erased, ty), test.span); + let ref_str_ty = Ty::new_imm_ref(tcx,re_erased, tcx.types.str_); let ref_str = self.temp(ref_str_ty, test.span); let deref = tcx.require_lang_item(LangItem::Deref, None); let method = trait_method(tcx, deref, sym::deref, [ty]); @@ -415,7 +415,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (Some((region, elem_ty, _)), _) | (None, Some((region, elem_ty, _))) => { let tcx = self.tcx; // make both a slice - ty = tcx.mk_imm_ref(*region, tcx.mk_slice(*elem_ty)); + ty = Ty::new_imm_ref(tcx, *region, Ty::new_slice(tcx, *elem_ty)); if opt_ref_ty.is_some() { let temp = self.temp(ty, source_info.span); self.cfg.push_assign( @@ -449,7 +449,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // non_scalar_compare called on non-reference type let temp = self.temp(ty, source_info.span); self.cfg.push_assign(block, source_info, temp, Rvalue::Use(expect)); - let ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, ty); + let ref_ty = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, ty); let ref_temp = self.temp(ref_ty, source_info.span); self.cfg.push_assign( @@ -871,7 +871,7 @@ fn trait_method<'tcx>( .find(|item| item.kind == ty::AssocKind::Fn) .expect("trait method not found"); - let method_ty = tcx.mk_fn_def(item.def_id, substs); + let method_ty = Ty::new_fn_def(tcx, item.def_id, substs); ConstantKind::zero_sized(method_ty) } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 49cbe3e2c9b..d828e71c7ac 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -614,7 +614,7 @@ fn construct_error(tcx: TyCtxt<'_>, def: LocalDefId, err: ErrorGuaranteed) -> Bo let generator_kind = tcx.generator_kind(def); let body_owner_kind = tcx.hir().body_owner_kind(def); - let ty = tcx.ty_error(err); + let ty = Ty::new_error(tcx, err); let num_params = match body_owner_kind { hir::BodyOwnerKind::Fn => tcx.fn_sig(def).skip_binder().inputs().skip_binder().len(), hir::BodyOwnerKind::Closure => { @@ -942,7 +942,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match self.unit_temp { Some(tmp) => tmp, None => { - let ty = self.tcx.mk_unit(); + let ty = Ty::new_unit(self.tcx); let fn_span = self.fn_span; let tmp = self.temp(ty, fn_span); self.unit_temp = Some(tmp); diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 7c0fbc6f81c..72374102c8c 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -91,6 +91,7 @@ use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::thir::{Expr, LintLevel}; +use rustc_middle::ty::Ty; use rustc_span::{Span, DUMMY_SP}; #[derive(Debug)] @@ -724,7 +725,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Add a dummy `Assign` statement to the CFG, with the span for the source code's `continue` // statement. fn add_dummy_assignment(&mut self, span: Span, block: BasicBlock, source_info: SourceInfo) { - let local_decl = LocalDecl::new(self.tcx.mk_unit(), span).internal(); + let local_decl = LocalDecl::new(Ty::new_unit(self.tcx), span).internal(); let temp_place = Place::from(self.local_decls.push(local_decl)); self.cfg.push_assign_unit(block, source_info, temp_place, self.tcx); } diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index a7be8e3c903..fbb74650faa 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -79,5 +79,5 @@ pub(crate) fn lit_to_const<'tcx>( _ => return Err(LitToConstError::TypeError), }; - Ok(tcx.mk_const(valtree, ty)) + Ok(ty::Const::new_value(tcx, valtree, ty)) } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 791c10c1748..a5c141b71f6 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -143,9 +143,11 @@ impl<'tcx> Cx<'tcx> { expr = Expr { temp_lifetime, - ty: self - .tcx - .mk_ref(deref.region, ty::TypeAndMut { ty: expr.ty, mutbl: deref.mutbl }), + ty: Ty::new_ref( + self.tcx, + deref.region, + ty::TypeAndMut { ty: expr.ty, mutbl: deref.mutbl }, + ), span, kind: ExprKind::Borrow { borrow_kind: deref.mutbl.to_borrow_kind(), @@ -308,7 +310,7 @@ impl<'tcx> Cx<'tcx> { let arg_tys = args.iter().map(|e| self.typeck_results().expr_ty_adjusted(e)); let tupled_args = Expr { - ty: tcx.mk_tup_from_iter(arg_tys), + ty: Ty::new_tup_from_iter(tcx, arg_tys), temp_lifetime, span: expr.span, kind: ExprKind::Tuple { fields: self.mirror_exprs(args) }, @@ -855,7 +857,11 @@ impl<'tcx> Cx<'tcx> { let user_ty = self.user_substs_applied_to_res(expr.hir_id, Res::Def(kind, def_id)); debug!("method_callee: user_ty={:?}", user_ty); ( - self.tcx().mk_fn_def(def_id, self.typeck_results().node_substs(expr.hir_id)), + Ty::new_fn_def( + self.tcx(), + def_id, + self.typeck_results().node_substs(expr.hir_id), + ), user_ty, ) } @@ -1008,7 +1014,7 @@ impl<'tcx> Cx<'tcx> { let ty::Ref(region, _, mutbl) = *self.thir[args[0]].ty.kind() else { span_bug!(span, "overloaded_place: receiver is not a reference"); }; - let ref_ty = self.tcx.mk_ref(region, ty::TypeAndMut { ty: place_ty, mutbl }); + let ref_ty = Ty::new_ref(self.tcx, region, ty::TypeAndMut { ty: place_ty, mutbl }); // construct the complete expression `foo()` for the overloaded call, // which will yield the &T type diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index d00fb754c64..e6a98d1aab0 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -15,7 +15,7 @@ use rustc_hir::HirId; use rustc_hir::Node; use rustc_middle::middle::region; use rustc_middle::thir::*; -use rustc_middle::ty::{self, RvalueScopes, TyCtxt}; +use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt}; use rustc_span::Span; pub(crate) fn thir_body( @@ -40,7 +40,7 @@ pub(crate) fn thir_body( // It will always be `()` in this case. if tcx.def_kind(owner_def) == DefKind::Generator && body.params.is_empty() { cx.thir.params.push(Param { - ty: tcx.mk_unit(), + ty: Ty::new_unit(tcx), pat: None, ty_span: None, self_kind: None, diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index a2e00d3bfc5..050b01294b4 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -380,7 +380,9 @@ impl<'tcx> ConstToPat<'tcx> { ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() { // `&str` is represented as a valtree, let's keep using this // optimization for now. - ty::Str => PatKind::Constant { value: mir::ConstantKind::Ty(tcx.mk_const(cv, ty)) }, + ty::Str => PatKind::Constant { + value: mir::ConstantKind::Ty(ty::Const::new_value(tcx, cv, ty)), + }, // Backwards compatibility hack: support references to non-structural types, // but hard error if we aren't behind a double reference. We could just use // the fallback code path below, but that would allow *more* of this fishy @@ -427,7 +429,7 @@ impl<'tcx> ConstToPat<'tcx> { // arrays. let pointee_ty = match *pointee_ty.kind() { ty::Array(elem_ty, _) if self.treat_byte_string_as_slice => { - tcx.mk_slice(elem_ty) + Ty::new_slice(tcx, elem_ty) } _ => *pointee_ty, }; @@ -438,9 +440,9 @@ impl<'tcx> ConstToPat<'tcx> { } } }, - ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::FnDef(..) => { - PatKind::Constant { value: mir::ConstantKind::Ty(tcx.mk_const(cv, ty)) } - } + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::FnDef(..) => PatKind::Constant { + value: mir::ConstantKind::Ty(ty::Const::new_value(tcx, cv, ty)), + }, ty::FnPtr(..) | ty::RawPtr(..) => unreachable!(), _ => { self.saw_const_match_error.set(true); diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index c30c4b65939..60099592784 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -525,7 +525,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { .tcx .const_eval_global_id_for_typeck(param_env_reveal_all, cid, Some(span)) .map(|val| match val { - Some(valtree) => mir::ConstantKind::Ty(self.tcx.mk_const(valtree, ty)), + Some(valtree) => mir::ConstantKind::Ty(ty::Const::new_value(self.tcx, valtree, ty)), None => mir::ConstantKind::Val( self.tcx .const_eval_global_id(param_env_reveal_all, cid, Some(span)) @@ -631,7 +631,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { if let Ok(Some(valtree)) = self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span)) { - self.const_to_pat(ConstantKind::Ty(self.tcx.mk_const(valtree, ty)), id, span, None).kind + self.const_to_pat( + ConstantKind::Ty(ty::Const::new_value(self.tcx, valtree, ty)), + id, + span, + None, + ) + .kind } else { // If that fails, convert it to an opaque constant pattern. match tcx.const_eval_resolve(self.param_env, uneval, None) { diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index c0102b15a16..0540a5e943b 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -423,7 +423,7 @@ where let unique_ty = adt.non_enum_variant().fields[FieldIdx::new(0)].ty(self.tcx(), substs); let unique_variant = unique_ty.ty_adt_def().unwrap().non_enum_variant(); let nonnull_ty = unique_variant.fields[FieldIdx::from_u32(0)].ty(self.tcx(), substs); - let ptr_ty = self.tcx().mk_imm_ptr(substs[0].expect_ty()); + let ptr_ty = Ty::new_imm_ptr(self.tcx(), substs[0].expect_ty()); let unique_place = self.tcx().mk_place_field(self.place, FieldIdx::new(0), unique_ty); let nonnull_place = self.tcx().mk_place_field(unique_place, FieldIdx::new(0), nonnull_ty); @@ -628,10 +628,13 @@ where let drop_fn = tcx.associated_item_def_ids(drop_trait)[0]; let ty = self.place_ty(self.place); - let ref_ty = - tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut }); + let ref_ty = Ty::new_ref( + tcx, + tcx.lifetimes.re_erased, + ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut }, + ); let ref_place = self.new_temp(ref_ty); - let unit_temp = Place::from(self.new_temp(tcx.mk_unit())); + let unit_temp = Place::from(self.new_temp(Ty::new_unit(tcx))); let result = BasicBlockData { statements: vec![self.assign( @@ -693,7 +696,7 @@ where let move_ = |place: Place<'tcx>| Operand::Move(place); let tcx = self.tcx(); - let ptr_ty = tcx.mk_ptr(ty::TypeAndMut { ty: ety, mutbl: hir::Mutability::Mut }); + let ptr_ty = Ty::new_ptr(tcx, ty::TypeAndMut { ty: ety, mutbl: hir::Mutability::Mut }); let ptr = Place::from(self.new_temp(ptr_ty)); let can_go = Place::from(self.new_temp(tcx.types.bool)); let one = self.constant_usize(1); diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index 05c54ab3097..4892ace53e3 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -155,7 +155,7 @@ fn insert_alignment_check<'tcx>( new_block: BasicBlock, ) { // Cast the pointer to a *const () - let const_raw_ptr = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not }); + let const_raw_ptr = Ty::new_ptr(tcx, TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not }); let rvalue = Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(pointer), const_raw_ptr); let thin_ptr = local_decls.push(LocalDecl::with_source_info(const_raw_ptr, source_info)).into(); block_data diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs index f31653caa49..cc0d7d51b60 100644 --- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs +++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs @@ -21,7 +21,7 @@ pub fn build_ptr_tys<'tcx>( let substs = tcx.mk_substs(&[pointee.into()]); let unique_ty = tcx.type_of(unique_did).subst(tcx, substs); let nonnull_ty = tcx.type_of(nonnull_did).subst(tcx, substs); - let ptr_ty = tcx.mk_imm_ptr(pointee); + let ptr_ty = Ty::new_imm_ptr(tcx, pointee); (unique_ty, nonnull_ty, ptr_ty) } diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 029fb2e9ba0..264bc61f1b3 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -413,8 +413,11 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { fn make_generator_state_argument_indirect<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let gen_ty = body.local_decls.raw[1].ty; - let ref_gen_ty = - tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty: gen_ty, mutbl: Mutability::Mut }); + let ref_gen_ty = Ty::new_ref( + tcx, + tcx.lifetimes.re_erased, + ty::TypeAndMut { ty: gen_ty, mutbl: Mutability::Mut }, + ); // Replace the by value generator argument body.local_decls.raw[1].ty = ref_gen_ty; @@ -429,7 +432,7 @@ fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body let pin_did = tcx.require_lang_item(LangItem::Pin, Some(body.span)); let pin_adt_ref = tcx.adt_def(pin_did); let substs = tcx.mk_substs(&[ref_gen_ty.into()]); - let pin_ref_gen_ty = tcx.mk_adt(pin_adt_ref, substs); + let pin_ref_gen_ty = Ty::new_adt(tcx, pin_adt_ref, substs); // Replace the by ref generator argument body.local_decls.raw[1].ty = pin_ref_gen_ty; @@ -481,7 +484,7 @@ fn replace_local<'tcx>( /// still using the `ResumeTy` indirection for the time being, and that indirection /// is removed here. After this transform, the generator body only knows about `&mut Context<'_>`. fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let context_mut_ref = tcx.mk_task_context(); + let context_mut_ref = Ty::new_task_context(tcx); // replace the type of the `resume` argument replace_resume_ty_local(tcx, body, Local::new(2), context_mut_ref); @@ -1130,13 +1133,13 @@ fn create_generator_drop_shim<'tcx>( } // Replace the return variable - body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(tcx.mk_unit(), source_info); + body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(Ty::new_unit(tcx), source_info); make_generator_state_argument_indirect(tcx, &mut body); // Change the generator argument from &mut to *mut body.local_decls[SELF_ARG] = LocalDecl::with_source_info( - tcx.mk_ptr(ty::TypeAndMut { ty: gen_ty, mutbl: hir::Mutability::Mut }), + Ty::new_ptr(tcx, ty::TypeAndMut { ty: gen_ty, mutbl: hir::Mutability::Mut }), source_info, ); @@ -1493,7 +1496,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform { let state_substs = tcx.mk_substs(&[yield_ty.into(), body.return_ty().into()]); (state_adt_ref, state_substs) }; - let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); + let ret_ty = Ty::new_adt(tcx, state_adt_ref, state_substs); // We rename RETURN_PLACE which has type mir.return_ty to new_ret_local // RETURN_PLACE then is a fresh unused local with type ret_ty. @@ -1509,8 +1512,11 @@ impl<'tcx> MirPass<'tcx> for StateTransform { // case there is no `Assign` to it that the transform can turn into a store to the generator // state. After the yield the slot in the generator state would then be uninitialized. let resume_local = Local::new(2); - let resume_ty = - if is_async_kind { tcx.mk_task_context() } else { body.local_decls[resume_local].ty }; + let resume_ty = if is_async_kind { + Ty::new_task_context(tcx) + } else { + body.local_decls[resume_local].ty + }; let new_resume_local = replace_local(resume_local, resume_ty, body, tcx); // When first entering the generator, move the resume argument into its new local. diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs index 430a6f6cef5..8ed4706e172 100644 --- a/compiler/rustc_mir_transform/src/large_enums.rs +++ b/compiler/rustc_mir_transform/src/large_enums.rs @@ -141,7 +141,7 @@ impl EnumSizeOpt { self.candidate(tcx, param_env, ty, &mut alloc_cache)?; let alloc = tcx.global_alloc(alloc_id).unwrap_memory(); - let tmp_ty = tcx.mk_array(tcx.types.usize, num_variants as u64); + let tmp_ty = Ty::new_array(tcx, tcx.types.usize, num_variants as u64); let size_array_local = local_decls.push(LocalDecl::new(tmp_ty, span)); let store_live = Statement { @@ -208,8 +208,9 @@ impl EnumSizeOpt { ))), }; - let dst = - Place::from(local_decls.push(LocalDecl::new(tcx.mk_mut_ptr(ty), span))); + let dst = Place::from( + local_decls.push(LocalDecl::new(Ty::new_mut_ptr(tcx, ty), span)), + ); let dst_ptr = Statement { source_info, @@ -219,7 +220,7 @@ impl EnumSizeOpt { ))), }; - let dst_cast_ty = tcx.mk_mut_ptr(tcx.types.u8); + let dst_cast_ty = Ty::new_mut_ptr(tcx, tcx.types.u8); let dst_cast_place = Place::from(local_decls.push(LocalDecl::new(dst_cast_ty, span))); @@ -231,8 +232,9 @@ impl EnumSizeOpt { ))), }; - let src = - Place::from(local_decls.push(LocalDecl::new(tcx.mk_imm_ptr(ty), span))); + let src = Place::from( + local_decls.push(LocalDecl::new(Ty::new_imm_ptr(tcx, ty), span)), + ); let src_ptr = Statement { source_info, @@ -242,7 +244,7 @@ impl EnumSizeOpt { ))), }; - let src_cast_ty = tcx.mk_imm_ptr(tcx.types.u8); + let src_cast_ty = Ty::new_imm_ptr(tcx, tcx.types.u8); let src_cast_place = Place::from(local_decls.push(LocalDecl::new(src_cast_ty, span))); diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 500595e9f50..b176db3c9e0 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -485,7 +485,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { let tcx = self.tcx; // `func == Clone::clone(&ty) -> ty` - let func_ty = tcx.mk_fn_def(self.def_id, [ty]); + let func_ty = Ty::new_fn_def(tcx, self.def_id, [ty]); let func = Operand::Constant(Box::new(Constant { span: self.span, user_ty: None, @@ -494,7 +494,11 @@ impl<'tcx> CloneShimBuilder<'tcx> { let ref_loc = self.make_place( Mutability::Not, - tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty, mutbl: hir::Mutability::Not }), + Ty::new_ref( + tcx, + tcx.lifetimes.re_erased, + ty::TypeAndMut { ty, mutbl: hir::Mutability::Not }, + ), ); // `let ref_loc: &ty = &src;` @@ -644,7 +648,7 @@ fn build_call_shim<'tcx>( let untuple_args = sig.inputs(); // Create substitutions for the `Self` and `Args` generic parameters of the shim body. - let arg_tup = tcx.mk_tup(untuple_args); + let arg_tup = Ty::new_tup(tcx, untuple_args); (Some([ty.into(), arg_tup.into()]), Some(untuple_args)) } else { @@ -680,9 +684,9 @@ fn build_call_shim<'tcx>( *self_arg = match rcvr_adjustment.unwrap() { Adjustment::Identity => fnty, Adjustment::Deref { source } => match source { - DerefSource::ImmRef => tcx.mk_imm_ref(tcx.lifetimes.re_erased, fnty), - DerefSource::MutRef => tcx.mk_mut_ref(tcx.lifetimes.re_erased, fnty), - DerefSource::MutPtr => tcx.mk_mut_ptr(fnty), + DerefSource::ImmRef => Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, fnty), + DerefSource::MutRef => Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, fnty), + DerefSource::MutPtr => Ty::new_mut_ptr(tcx, fnty), }, Adjustment::RefMut => bug!("`RefMut` is never used with indirect calls: {instance:?}"), }; @@ -696,7 +700,7 @@ fn build_call_shim<'tcx>( let mut inputs_and_output = sig.inputs_and_output.to_vec(); let self_arg = &mut inputs_and_output[0]; debug_assert!(tcx.generics_of(def_id).has_self && *self_arg == tcx.types.self_param); - *self_arg = tcx.mk_mut_ptr(*self_arg); + *self_arg = Ty::new_mut_ptr(tcx, *self_arg); sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output); } @@ -720,7 +724,8 @@ fn build_call_shim<'tcx>( // let rcvr = &mut rcvr; let ref_rcvr = local_decls.push( LocalDecl::new( - tcx.mk_ref( + Ty::new_ref( + tcx, tcx.lifetimes.re_erased, ty::TypeAndMut { ty: sig.inputs()[0], mutbl: hir::Mutability::Mut }, ), @@ -946,7 +951,7 @@ fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'t let rvalue = Rvalue::Cast( CastKind::FnPtrToPtr, Operand::Move(Place::from(Local::new(1))), - tcx.mk_imm_ptr(tcx.types.unit), + Ty::new_imm_ptr(tcx, tcx.types.unit), ); let stmt = Statement { source_info, diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index e663f4486f7..f4535fbd58f 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -187,7 +187,13 @@ where } // Ensure CGUs are sorted by name, so that we get deterministic results. - assert!(codegen_units.is_sorted_by(|a, b| Some(a.name().as_str().cmp(b.name().as_str())))); + if !codegen_units.is_sorted_by(|a, b| Some(a.name().as_str().cmp(b.name().as_str()))) { + let mut names = String::new(); + for cgu in codegen_units.iter() { + names += &format!("- {}\n", cgu.name()); + } + bug!("unsorted CGUs:\n{names}"); + } codegen_units } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 228eff1269f..0ce6a570d25 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -605,6 +605,22 @@ impl<'a> Parser<'a> { } } + if let TokenKind::Ident(prev, _) = &self.prev_token.kind + && let TokenKind::Ident(cur, _) = &self.token.kind + { + let concat = Symbol::intern(&format!("{}{}", prev, cur)); + let ident = Ident::new(concat, DUMMY_SP); + if ident.is_used_keyword() || ident.is_reserved() || ident.is_raw_guess() { + let span = self.prev_token.span.to(self.token.span); + err.span_suggestion_verbose( + span, + format!("consider removing the space to spell keyword `{}`", concat), + concat, + Applicability::MachineApplicable, + ); + } + } + // `pub` may be used for an item or `pub(crate)` if self.prev_token.is_ident_named(sym::public) && (self.token.can_begin_item() diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 3783ec41b7e..1470180dea7 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2182,7 +2182,11 @@ impl<'a> Parser<'a> { // `extern ABI fn` || self.check_keyword_case(kw::Extern, case) && self.look_ahead(1, |t| t.can_begin_literal_maybe_minus()) - && self.look_ahead(2, |t| t.is_keyword_case(kw::Fn, case)) + && (self.look_ahead(2, |t| t.is_keyword_case(kw::Fn, case)) || + // this branch is only for better diagnostic in later, `pub` is not allowed here + (self.may_recover() + && self.look_ahead(2, |t| t.is_keyword(kw::Pub)) + && self.look_ahead(3, |t| t.is_keyword_case(kw::Fn, case)))) } /// Parses all the "front matter" (or "qualifiers") for a `fn` declaration, diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 055006373ef..4fcee9396ed 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -174,7 +174,6 @@ where } ty::ClauseKind::ConstEvaluatable(ct) => ct.visit_with(self), ty::ClauseKind::WellFormed(arg) => arg.visit_with(self), - ty::ClauseKind::TypeWellFormedFromEnv(_) => bug!("unexpected clause: {clause}"), } } diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index b2bc33c7e0d..4adb4eb7475 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -126,18 +126,13 @@ where #[cold] #[inline(never)] -fn mk_cycle<Q, Qcx>( - query: Q, - qcx: Qcx, - cycle_error: CycleError<Qcx::DepKind>, - handler: HandleCycleError, -) -> Q::Value +fn mk_cycle<Q, Qcx>(query: Q, qcx: Qcx, cycle_error: CycleError<Qcx::DepKind>) -> Q::Value where Q: QueryConfig<Qcx>, Qcx: QueryContext, { let error = report_cycle(qcx.dep_context().sess(), &cycle_error); - handle_cycle_error(query, qcx, &cycle_error, error, handler) + handle_cycle_error(query, qcx, &cycle_error, error) } fn handle_cycle_error<Q, Qcx>( @@ -145,14 +140,13 @@ fn handle_cycle_error<Q, Qcx>( qcx: Qcx, cycle_error: &CycleError<Qcx::DepKind>, mut error: DiagnosticBuilder<'_, ErrorGuaranteed>, - handler: HandleCycleError, ) -> Q::Value where Q: QueryConfig<Qcx>, Qcx: QueryContext, { use HandleCycleError::*; - match handler { + match query.handle_cycle_error() { Error => { error.emit(); query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle) @@ -277,7 +271,7 @@ where &qcx.current_query_job(), span, ); - (mk_cycle(query, qcx, error, query.handle_cycle_error()), None) + (mk_cycle(query, qcx, error), None) } #[inline(always)] @@ -314,7 +308,7 @@ where (v, Some(index)) } - Err(cycle) => (mk_cycle(query, qcx, cycle, query.handle_cycle_error()), None), + Err(cycle) => (mk_cycle(query, qcx, cycle), None), } } diff --git a/compiler/rustc_query_system/src/values.rs b/compiler/rustc_query_system/src/values.rs index b6e2cfa3dca..ce551078cc0 100644 --- a/compiler/rustc_query_system/src/values.rs +++ b/compiler/rustc_query_system/src/values.rs @@ -6,10 +6,13 @@ pub trait Value<Tcx: DepContext, D: DepKind>: Sized { } impl<Tcx: DepContext, T, D: DepKind> Value<Tcx, D> for T { - default fn from_cycle_error(tcx: Tcx, _: &[QueryInfo<D>]) -> T { + default fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo<D>]) -> T { tcx.sess().abort_if_errors(); // Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's // non-trivial to define it earlier. - panic!("Value::from_cycle_error called without errors"); + panic!( + "<{} as Value>::from_cycle_error called without errors: {cycle:#?}", + std::any::type_name::<T>() + ); } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 72777733345..e6ceedddfa1 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -6,10 +6,10 @@ //! Imports are also considered items and placed into modules here, but not resolved yet. use crate::def_collector::collect_definitions; -use crate::imports::{Import, ImportKind}; +use crate::imports::{ImportData, ImportKind}; use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::Namespace::{self, MacroNS, TypeNS, ValueNS}; -use crate::{errors, BindingKey, MacroData}; +use crate::{errors, BindingKey, MacroData, NameBindingData}; use crate::{Determinacy, ExternPreludeEntry, Finalize, Module, ModuleKind, ModuleOrUniformRoot}; use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PerNS, ResolutionError}; use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, VisResolutionError}; @@ -31,15 +31,14 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; use std::cell::Cell; -use std::ptr; type Res = def::Res<NodeId>; impl<'a, Id: Into<DefId>> ToNameBinding<'a> for (Module<'a>, ty::Visibility<Id>, Span, LocalExpnId) { - fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { - arenas.alloc_name_binding(NameBinding { + fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> NameBinding<'a> { + arenas.alloc_name_binding(NameBindingData { kind: NameBindingKind::Module(self.0), ambiguity: None, vis: self.1.to_def_id(), @@ -50,8 +49,8 @@ impl<'a, Id: Into<DefId>> ToNameBinding<'a> } impl<'a, Id: Into<DefId>> ToNameBinding<'a> for (Res, ty::Visibility<Id>, Span, LocalExpnId) { - fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { - arenas.alloc_name_binding(NameBinding { + fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> NameBinding<'a> { + arenas.alloc_name_binding(NameBindingData { kind: NameBindingKind::Res(self.0), ambiguity: None, vis: self.1.to_def_id(), @@ -71,7 +70,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let binding = def.to_name_binding(self.arenas); let key = self.new_disambiguated_key(ident, ns); if let Err(old_binding) = self.try_define(parent, key, binding) { - self.report_conflict(parent, ident, ns, old_binding, &binding); + self.report_conflict(parent, ident, ns, old_binding, binding); } } @@ -142,8 +141,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Some(def_id) => self.macro_def_scope(def_id), None => expn_id .as_local() - .and_then(|expn_id| self.ast_transform_scopes.get(&expn_id)) - .unwrap_or(&self.graph_root), + .and_then(|expn_id| self.ast_transform_scopes.get(&expn_id).copied()) + .unwrap_or(self.graph_root), } } @@ -354,7 +353,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { vis: ty::Visibility, ) { let current_module = self.parent_scope.module; - let import = self.r.arenas.alloc_import(Import { + let import = self.r.arenas.alloc_import(ImportData { kind, parent_scope: self.parent_scope, module_path, @@ -378,7 +377,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { if !type_ns_only || ns == TypeNS { let key = BindingKey::new(target, ns); let mut resolution = this.resolution(current_module, key).borrow_mut(); - resolution.add_single_import(import); + resolution.single_imports.insert(import); } }); } @@ -848,7 +847,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { (used, Some(ModuleOrUniformRoot::Module(module)), binding) }) .unwrap_or((true, None, self.r.dummy_binding)); - let import = self.r.arenas.alloc_import(Import { + let import = self.r.arenas.alloc_import(ImportData { kind: ImportKind::ExternCrate { source: orig_name, target: ident, id: item.id }, root_id: item.id, parent_scope: self.parent_scope, @@ -864,7 +863,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { }); self.r.potentially_unused_imports.push(import); let imported_binding = self.r.import(binding, import); - if ptr::eq(parent, self.r.graph_root) { + if parent == self.r.graph_root { if let Some(entry) = self.r.extern_prelude.get(&ident.normalize_to_macros_2_0()) { if expansion != LocalExpnId::ROOT && orig_name.is_some() @@ -996,7 +995,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { fn add_macro_use_binding( &mut self, name: Symbol, - binding: &'a NameBinding<'a>, + binding: NameBinding<'a>, span: Span, allow_shadowing: bool, ) { @@ -1058,7 +1057,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } let macro_use_import = |this: &Self, span| { - this.r.arenas.alloc_import(Import { + this.r.arenas.alloc_import(ImportData { kind: ImportKind::MacroUse, root_id: item.id, parent_scope: this.parent_scope, @@ -1228,7 +1227,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r.set_binding_parent_module(binding, parent_scope.module); self.r.all_macro_rules.insert(ident.name, res); if is_macro_export { - let import = self.r.arenas.alloc_import(Import { + let import = self.r.arenas.alloc_import(ImportData { kind: ImportKind::MacroExport, root_id: item.id, parent_scope: self.parent_scope, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index d9e4974626d..d3dcdfa4275 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1,5 +1,3 @@ -use std::ptr; - use rustc_ast::expand::StrippedCfgItem; use rustc_ast::ptr::P; use rustc_ast::visit::{self, Visitor}; @@ -182,13 +180,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - pub(crate) fn report_conflict<'b>( + pub(crate) fn report_conflict( &mut self, parent: Module<'_>, ident: Ident, ns: Namespace, - new_binding: &NameBinding<'b>, - old_binding: &NameBinding<'b>, + new_binding: NameBinding<'a>, + old_binding: NameBinding<'a>, ) { // Error on the second of two conflicting names if old_binding.span.lo() > new_binding.span.lo() { @@ -262,7 +260,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // See https://github.com/rust-lang/rust/issues/32354 use NameBindingKind::Import; - let can_suggest = |binding: &NameBinding<'_>, import: &self::Import<'_>| { + let can_suggest = |binding: NameBinding<'_>, import: self::Import<'_>| { !binding.span.is_dummy() && !matches!(import.kind, ImportKind::MacroUse | ImportKind::MacroExport) }; @@ -272,22 +270,22 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { (Import { import: new, .. }, Import { import: old, .. }) if { (new.has_attributes || old.has_attributes) - && can_suggest(old_binding, old) - && can_suggest(new_binding, new) + && can_suggest(old_binding, *old) + && can_suggest(new_binding, *new) } => { if old.has_attributes { - Some((new, new_binding.span, true)) + Some((*new, new_binding.span, true)) } else { - Some((old, old_binding.span, true)) + Some((*old, old_binding.span, true)) } } // Otherwise prioritize the new binding. - (Import { import, .. }, other) if can_suggest(new_binding, import) => { - Some((import, new_binding.span, other.is_import())) + (Import { import, .. }, other) if can_suggest(new_binding, *import) => { + Some((*import, new_binding.span, other.is_import())) } - (other, Import { import, .. }) if can_suggest(old_binding, import) => { - Some((import, old_binding.span, other.is_import())) + (other, Import { import, .. }) if can_suggest(old_binding, *import) => { + Some((*import, old_binding.span, other.is_import())) } _ => None, }; @@ -341,7 +339,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &self, err: &mut Diagnostic, name: Symbol, - import: &Import<'_>, + import: Import<'_>, binding_span: Span, ) { let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() { @@ -413,7 +411,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn add_suggestion_for_duplicate_nested_use( &self, err: &mut Diagnostic, - import: &Import<'_>, + import: Import<'_>, binding_span: Span, ) { assert!(import.is_nested()); @@ -455,7 +453,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &mut self, finalize: Option<Finalize>, path: &[Segment], - second_binding: Option<&NameBinding<'_>>, + second_binding: Option<NameBinding<'_>>, ) { let Some(Finalize { node_id, root_span, .. }) = finalize else { return; @@ -1198,7 +1196,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // avoid suggesting anything with a hygienic name if ident.name == lookup_ident.name && ns == namespace - && !ptr::eq(in_module, parent_scope.module) + && in_module != parent_scope.module && !ident.span.normalize_to_macros_2_0().from_expansion() { let res = name_binding.res(); @@ -1515,7 +1513,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { true } - fn binding_description(&self, b: &NameBinding<'_>, ident: Ident, from_prelude: bool) -> String { + fn binding_description(&self, b: NameBinding<'_>, ident: Ident, from_prelude: bool) -> String { let res = b.res(); if b.span.is_dummy() || !self.tcx.sess.source_map().is_span_accessible(b.span) { // These already contain the "built-in" prefix or look bad with it. @@ -1555,7 +1553,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { err.span_label(ident.span, "ambiguous name"); err.note(format!("ambiguous because of {}", kind.descr())); - let mut could_refer_to = |b: &NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| { + let mut could_refer_to = |b: NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| { let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude); let note_msg = format!("`{ident}` could{also} refer to {what}"); @@ -1595,7 +1593,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// If the binding refers to a tuple struct constructor with fields, /// returns the span of its fields. - fn ctor_fields_span(&self, binding: &NameBinding<'_>) -> Option<Span> { + fn ctor_fields_span(&self, binding: NameBinding<'_>) -> Option<Span> { if let NameBindingKind::Res(Res::Def( DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), ctor_def_id, @@ -1622,7 +1620,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if ctor_fields_span.is_some() { plain_descr + " constructor" } else { plain_descr }; let import_descr = nonimport_descr.clone() + " import"; let get_descr = - |b: &NameBinding<'_>| if b.is_import() { &import_descr } else { &nonimport_descr }; + |b: NameBinding<'_>| if b.is_import() { &import_descr } else { &nonimport_descr }; // Print the primary message. let descr = get_descr(binding); @@ -1702,7 +1700,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { _ => None, }; - let first = ptr::eq(binding, first_binding); + let first = binding == first_binding; let msg = format!( "{and_refers_to}the {item} `{name}`{which} is defined here{dots}", and_refers_to = if first { "" } else { "...and refers to " }, @@ -1732,7 +1730,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { pub(crate) fn find_similarly_named_module_or_crate( &mut self, ident: Symbol, - current_module: &Module<'a>, + current_module: Module<'a>, ) -> Option<Symbol> { let mut candidates = self .extern_prelude @@ -1742,7 +1740,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.module_map .iter() .filter(|(_, module)| { - current_module.is_ancestor_of(module) && !ptr::eq(current_module, *module) + current_module.is_ancestor_of(**module) && current_module != **module }) .flat_map(|(_, module)| module.kind.name()), ) @@ -1762,7 +1760,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { opt_ns: Option<Namespace>, // `None` indicates a module path in import parent_scope: &ParentScope<'a>, ribs: Option<&PerNS<Vec<Rib<'a>>>>, - ignore_binding: Option<&'a NameBinding<'a>>, + ignore_binding: Option<NameBinding<'a>>, module: Option<ModuleOrUniformRoot<'a>>, failed_segment_idx: usize, ident: Ident, @@ -1945,7 +1943,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } suggestion = suggestion.or_else(|| { - self.find_similarly_named_module_or_crate(ident.name, &parent_scope.module).map( + self.find_similarly_named_module_or_crate(ident.name, parent_scope.module).map( |sugg| { ( vec![(ident.span, sugg.to_string())], @@ -2114,7 +2112,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// ``` pub(crate) fn check_for_module_export_macro( &mut self, - import: &'a Import<'a>, + import: Import<'a>, module: ModuleOrUniformRoot<'a>, ident: Ident, ) -> Option<(Option<Suggestion>, Option<String>)> { @@ -2126,9 +2124,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { crate_module = parent; } - if ModuleOrUniformRoot::same_def(ModuleOrUniformRoot::Module(crate_module), module) { - // Don't make a suggestion if the import was already from the root of the - // crate. + if module == ModuleOrUniformRoot::Module(crate_module) { + // Don't make a suggestion if the import was already from the root of the crate. return None; } diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 4863c9f4790..eb210532f51 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -5,7 +5,6 @@ use rustc_ast::visit::Visitor; use rustc_ast::Crate; use rustc_ast::EnumDef; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::intern::Interned; use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_middle::middle::privacy::Level; @@ -13,12 +12,10 @@ use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility}; use rustc_middle::ty::Visibility; use std::mem; -type ImportId<'a> = Interned<'a, NameBinding<'a>>; - #[derive(Clone, Copy)] enum ParentId<'a> { Def(LocalDefId), - Import(ImportId<'a>), + Import(NameBinding<'a>), } impl ParentId<'_> { @@ -36,7 +33,7 @@ pub(crate) struct EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { /// While walking import chains we need to track effective visibilities per-binding, and def id /// keys in `Resolver::effective_visibilities` are not enough for that, because multiple /// bindings can correspond to a single def id in imports. So we keep a separate table. - import_effective_visibilities: EffectiveVisibilities<ImportId<'a>>, + import_effective_visibilities: EffectiveVisibilities<NameBinding<'a>>, // It's possible to recalculate this at any point, but it's relatively expensive. current_private_vis: Visibility, changed: bool, @@ -47,7 +44,7 @@ impl Resolver<'_, '_> { self.get_nearest_non_block_module(def_id.to_def_id()).nearest_parent_mod().expect_local() } - fn private_vis_import(&mut self, binding: ImportId<'_>) -> Visibility { + fn private_vis_import(&mut self, binding: NameBinding<'_>) -> Visibility { let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() }; Visibility::Restricted( import @@ -75,7 +72,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { pub(crate) fn compute_effective_visibilities<'c>( r: &'r mut Resolver<'a, 'tcx>, krate: &'c Crate, - ) -> FxHashSet<Interned<'a, NameBinding<'a>>> { + ) -> FxHashSet<NameBinding<'a>> { let mut visitor = EffectiveVisibilitiesVisitor { r, def_effective_visibilities: Default::default(), @@ -133,8 +130,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { // lint. For all bindings added to the table this way `is_ambiguity` returns true. let mut parent_id = ParentId::Def(module_id); while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind { - let binding_id = ImportId::new_unchecked(binding); - self.update_import(binding_id, parent_id); + self.update_import(binding, parent_id); if binding.ambiguity.is_some() { // Stop at the root ambiguity, further bindings in the chain should not @@ -143,7 +139,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { break; } - parent_id = ParentId::Import(binding_id); + parent_id = ParentId::Import(binding); binding = nested_binding; } @@ -192,7 +188,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { } } - fn update_import(&mut self, binding: ImportId<'a>, parent_id: ParentId<'a>) { + fn update_import(&mut self, binding: NameBinding<'a>, parent_id: ParentId<'a>) { let nominal_vis = binding.vis.expect_local(); let Some(cheap_private_vis) = self.may_update(nominal_vis, parent_id) else { return }; let inherited_eff_vis = self.effective_vis_or_private(parent_id); diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 36f01676e7e..520fab1f0c8 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -11,8 +11,6 @@ use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContex use rustc_span::symbol::{kw, Ident}; use rustc_span::{Span, DUMMY_SP}; -use std::ptr; - use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst}; use crate::late::{ ConstantHasGenerics, HasGenericParams, NoConstantGenericsReason, PathSource, Rib, RibKind, @@ -20,7 +18,7 @@ use crate::late::{ use crate::macros::{sub_namespace_match, MacroRulesScope}; use crate::BindingKey; use crate::{errors, AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize}; -use crate::{Import, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot}; +use crate::{ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot}; use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res}; use crate::{ResolutionError, Resolver, Scope, ScopeSet, Segment, ToNameBinding, Weak}; @@ -284,7 +282,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { parent_scope: &ParentScope<'a>, finalize: Option<Finalize>, ribs: &[Rib<'a>], - ignore_binding: Option<&'a NameBinding<'a>>, + ignore_binding: Option<NameBinding<'a>>, ) -> Option<LexicalScopeBinding<'a>> { assert!(ns == TypeNS || ns == ValueNS); let orig_ident = ident; @@ -378,8 +376,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { parent_scope: &ParentScope<'a>, finalize: Option<Finalize>, force: bool, - ignore_binding: Option<&'a NameBinding<'a>>, - ) -> Result<&'a NameBinding<'a>, Determinacy> { + ignore_binding: Option<NameBinding<'a>>, + ) -> Result<NameBinding<'a>, Determinacy> { bitflags::bitflags! { struct Flags: u8 { const MACRO_RULES = 1 << 0; @@ -415,7 +413,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // } // So we have to save the innermost solution and continue searching in outer scopes // to detect potential ambiguities. - let mut innermost_result: Option<(&NameBinding<'_>, Flags)> = None; + let mut innermost_result: Option<(NameBinding<'_>, Flags)> = None; let mut determinacy = Determinacy::Determined; // Go through all the scopes and try to resolve the name. @@ -538,7 +536,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ), ); } - let misc_flags = if ptr::eq(module, this.graph_root) { + let misc_flags = if module == this.graph_root { Flags::MISC_SUGGEST_CRATE } else if module.is_normal() { Flags::MISC_SUGGEST_SELF @@ -717,7 +715,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ident: Ident, ns: Namespace, parent_scope: &ParentScope<'a>, - ) -> Result<&'a NameBinding<'a>, Determinacy> { + ) -> Result<NameBinding<'a>, Determinacy> { self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, None, None) .map_err(|(determinacy, _)| determinacy) } @@ -730,8 +728,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ns: Namespace, parent_scope: &ParentScope<'a>, finalize: Option<Finalize>, - ignore_binding: Option<&'a NameBinding<'a>>, - ) -> Result<&'a NameBinding<'a>, Determinacy> { + ignore_binding: Option<NameBinding<'a>>, + ) -> Result<NameBinding<'a>, Determinacy> { self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, finalize, ignore_binding) .map_err(|(determinacy, _)| determinacy) } @@ -744,8 +742,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ns: Namespace, parent_scope: &ParentScope<'a>, finalize: Option<Finalize>, - ignore_binding: Option<&'a NameBinding<'a>>, - ) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> { + ignore_binding: Option<NameBinding<'a>>, + ) -> Result<NameBinding<'a>, (Determinacy, Weak)> { let tmp_parent_scope; let mut adjusted_parent_scope = parent_scope; match module { @@ -782,8 +780,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ns: Namespace, parent_scope: &ParentScope<'a>, finalize: Option<Finalize>, - ignore_binding: Option<&'a NameBinding<'a>>, - ) -> Result<&'a NameBinding<'a>, Determinacy> { + ignore_binding: Option<NameBinding<'a>>, + ) -> Result<NameBinding<'a>, Determinacy> { self.resolve_ident_in_module_unadjusted_ext( module, ident, @@ -809,8 +807,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { finalize: Option<Finalize>, // This binding should be ignored during in-module resolution, so that we don't get // "self-confirming" import resolutions during import validation and checking. - ignore_binding: Option<&'a NameBinding<'a>>, - ) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> { + ignore_binding: Option<NameBinding<'a>>, + ) -> Result<NameBinding<'a>, (Determinacy, Weak)> { let module = match module { ModuleOrUniformRoot::Module(module) => module, ModuleOrUniformRoot::CrateRootAndExternPrelude => { @@ -873,13 +871,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // binding if it exists. What we really want here is having two separate scopes in // a module - one for non-globs and one for globs, but until that's done use this // hack to avoid inconsistent resolution ICEs during import validation. - let binding = - [resolution.binding, resolution.shadowed_glob].into_iter().find_map(|binding| { - match (binding, ignore_binding) { - (Some(binding), Some(ignored)) if ptr::eq(binding, ignored) => None, - _ => binding, - } - }); + let binding = [resolution.binding, resolution.shadowed_glob] + .into_iter() + .find_map(|binding| if binding == ignore_binding { None } else { binding }); if let Some(Finalize { path_span, report_private, .. }) = finalize { let Some(binding) = binding else { @@ -917,11 +911,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } if !restricted_shadowing && binding.expansion != LocalExpnId::ROOT { - if let NameBindingKind::Import { - import: Import { kind: ImportKind::MacroExport, .. }, - .. - } = binding.kind - { + if let NameBindingKind::Import { import, .. } = binding.kind + && matches!(import.kind, ImportKind::MacroExport) { self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); } } @@ -930,7 +921,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { return Ok(binding); } - let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| { + let check_usable = |this: &mut Self, binding: NameBinding<'a>| { let usable = this.is_accessible_from(binding.vis, parent_scope.module); if usable { Ok(binding) } else { Err((Determined, Weak::No)) } }; @@ -955,7 +946,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } if let Some(ignored) = ignore_binding && let NameBindingKind::Import { import, .. } = ignored.kind && - ptr::eq(import, &**single_import) { + import == *single_import { // Ignore not just the binding itself, but if it has a shadowed_glob, // ignore that, too, because this loop is supposed to only process // named imports. @@ -1352,7 +1343,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { opt_ns: Option<Namespace>, // `None` indicates a module path in import parent_scope: &ParentScope<'a>, finalize: Option<Finalize>, - ignore_binding: Option<&'a NameBinding<'a>>, + ignore_binding: Option<NameBinding<'a>>, ) -> PathResult<'a> { self.resolve_path_with_ribs(path, opt_ns, parent_scope, finalize, None, ignore_binding) } @@ -1364,7 +1355,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { parent_scope: &ParentScope<'a>, finalize: Option<Finalize>, ribs: Option<&PerNS<Vec<Rib<'a>>>>, - ignore_binding: Option<&'a NameBinding<'a>>, + ignore_binding: Option<NameBinding<'a>>, ) -> PathResult<'a> { let mut module = None; let mut allow_super = true; diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 074f761c53b..d37fe783bba 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -12,7 +12,7 @@ use crate::{fluent_generated as fluent, Namespace::*}; use crate::{module_to_string, names_to_string, ImportSuggestion}; use crate::{AmbiguityKind, BindingKey, ModuleKind, ResolutionError, Resolver, Segment}; use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet}; -use crate::{NameBinding, NameBindingKind, PathResult}; +use crate::{NameBinding, NameBindingData, NameBindingKind, PathResult}; use rustc_ast::NodeId; use rustc_data_structures::fx::FxHashSet; @@ -35,7 +35,7 @@ use rustc_span::Span; use smallvec::SmallVec; use std::cell::Cell; -use std::{mem, ptr}; +use std::mem; type Res = def::Res<NodeId>; @@ -48,9 +48,9 @@ pub(crate) enum ImportKind<'a> { /// `target` in `use prefix::source as target`. target: Ident, /// Bindings to which `source` refers to. - source_bindings: PerNS<Cell<Result<&'a NameBinding<'a>, Determinacy>>>, + source_bindings: PerNS<Cell<Result<NameBinding<'a>, Determinacy>>>, /// Bindings introduced by `target`. - target_bindings: PerNS<Cell<Option<&'a NameBinding<'a>>>>, + target_bindings: PerNS<Cell<Option<NameBinding<'a>>>>, /// `true` for `...::{self [as target]}` imports, `false` otherwise. type_ns_only: bool, /// Did this import result from a nested import? ie. `use foo::{bar, baz};` @@ -135,7 +135,7 @@ impl<'a> std::fmt::Debug for ImportKind<'a> { /// One import. #[derive(Debug, Clone)] -pub(crate) struct Import<'a> { +pub(crate) struct ImportData<'a> { pub kind: ImportKind<'a>, /// Node ID of the "root" use item -- this is always the same as `ImportKind`'s `id` @@ -172,7 +172,11 @@ pub(crate) struct Import<'a> { pub used: Cell<bool>, } -impl<'a> Import<'a> { +/// All imports are unique and allocated on a same arena, +/// so we can use referential equality to compare them. +pub(crate) type Import<'a> = Interned<'a, ImportData<'a>>; + +impl<'a> ImportData<'a> { pub(crate) fn is_glob(&self) -> bool { matches!(self.kind, ImportKind::Glob { .. }) } @@ -214,15 +218,15 @@ impl<'a> Import<'a> { pub(crate) struct NameResolution<'a> { /// Single imports that may define the name in the namespace. /// Imports are arena-allocated, so it's ok to use pointers as keys. - pub single_imports: FxHashSet<Interned<'a, Import<'a>>>, + pub single_imports: FxHashSet<Import<'a>>, /// The least shadowable known binding for this name, or None if there are no known bindings. - pub binding: Option<&'a NameBinding<'a>>, - pub shadowed_glob: Option<&'a NameBinding<'a>>, + pub binding: Option<NameBinding<'a>>, + pub shadowed_glob: Option<NameBinding<'a>>, } impl<'a> NameResolution<'a> { /// Returns the binding for the name if it is known or None if it not known. - pub(crate) fn binding(&self) -> Option<&'a NameBinding<'a>> { + pub(crate) fn binding(&self) -> Option<NameBinding<'a>> { self.binding.and_then(|binding| { if !binding.is_glob_import() || self.single_imports.is_empty() { Some(binding) @@ -231,10 +235,6 @@ impl<'a> NameResolution<'a> { } }) } - - pub(crate) fn add_single_import(&mut self, import: &'a Import<'a>) { - self.single_imports.insert(Interned::new_unchecked(import)); - } } /// An error that may be transformed into a diagnostic later. Used to combine multiple unresolved @@ -250,15 +250,12 @@ struct UnresolvedImportError { // Reexports of the form `pub use foo as bar;` where `foo` is `extern crate foo;` // are permitted for backward-compatibility under a deprecation lint. -fn pub_use_of_private_extern_crate_hack(import: &Import<'_>, binding: &NameBinding<'_>) -> bool { +fn pub_use_of_private_extern_crate_hack(import: Import<'_>, binding: NameBinding<'_>) -> bool { match (&import.kind, &binding.kind) { - ( - ImportKind::Single { .. }, - NameBindingKind::Import { - import: Import { kind: ImportKind::ExternCrate { .. }, .. }, - .. - }, - ) => import.expect_vis().is_public(), + (ImportKind::Single { .. }, NameBindingKind::Import { import: binding_import, .. }) => { + matches!(binding_import.kind, ImportKind::ExternCrate { .. }) + && import.expect_vis().is_public() + } _ => false, } } @@ -266,11 +263,7 @@ fn pub_use_of_private_extern_crate_hack(import: &Import<'_>, binding: &NameBindi impl<'a, 'tcx> Resolver<'a, 'tcx> { /// Given a binding and an import that resolves to it, /// return the corresponding binding defined by the import. - pub(crate) fn import( - &self, - binding: &'a NameBinding<'a>, - import: &'a Import<'a>, - ) -> &'a NameBinding<'a> { + pub(crate) fn import(&self, binding: NameBinding<'a>, import: Import<'a>) -> NameBinding<'a> { let import_vis = import.expect_vis().to_def_id(); let vis = if binding.vis.is_at_least(import_vis, self.tcx) || pub_use_of_private_extern_crate_hack(import, binding) @@ -288,7 +281,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - self.arenas.alloc_name_binding(NameBinding { + self.arenas.alloc_name_binding(NameBindingData { kind: NameBindingKind::Import { binding, import, used: Cell::new(false) }, ambiguity: None, span: import.span, @@ -302,8 +295,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &mut self, module: Module<'a>, key: BindingKey, - binding: &'a NameBinding<'a>, - ) -> Result<(), &'a NameBinding<'a>> { + binding: NameBinding<'a>, + ) -> Result<(), NameBinding<'a>> { let res = binding.res(); self.check_reserved_macro_name(key.ident, res); self.set_binding_parent_module(binding, module); @@ -372,12 +365,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn ambiguity( &self, kind: AmbiguityKind, - primary_binding: &'a NameBinding<'a>, - secondary_binding: &'a NameBinding<'a>, - ) -> &'a NameBinding<'a> { - self.arenas.alloc_name_binding(NameBinding { + primary_binding: NameBinding<'a>, + secondary_binding: NameBinding<'a>, + ) -> NameBinding<'a> { + self.arenas.alloc_name_binding(NameBindingData { ambiguity: Some((secondary_binding, kind)), - ..primary_binding.clone() + ..(*primary_binding).clone() }) } @@ -395,13 +388,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let t = f(self, resolution); - match resolution.binding() { - _ if old_binding.is_some() => return t, - None => return t, - Some(binding) => match old_binding { - Some(old_binding) if ptr::eq(old_binding, binding) => return t, - _ => (binding, t), - }, + if old_binding.is_none() && let Some(binding) = resolution.binding() { + (binding, t) + } else { + return t; } }; @@ -414,7 +404,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { None => continue, }; if self.is_accessible_from(binding.vis, scope) { - let imported_binding = self.import(binding, import); + let imported_binding = self.import(binding, *import); let key = BindingKey { ident, ..key }; let _ = self.try_define(import.parent_scope.module, key, imported_binding); } @@ -425,7 +415,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Define a dummy resolution containing a `Res::Err` as a placeholder for a failed // or indeterminate resolution, also mark such failed imports as used to avoid duplicate diagnostics. - fn import_dummy_binding(&mut self, import: &'a Import<'a>, is_indeterminate: bool) { + fn import_dummy_binding(&mut self, import: Import<'a>, is_indeterminate: bool) { if let ImportKind::Single { target, ref target_bindings, .. } = import.kind { if !(is_indeterminate || target_bindings.iter().all(|binding| binding.get().is_none())) { @@ -463,7 +453,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { prev_indeterminate_count = indeterminate_count; indeterminate_count = 0; for import in mem::take(&mut self.indeterminate_imports) { - let import_indeterminate_count = self.resolve_import(&import); + let import_indeterminate_count = self.resolve_import(import); indeterminate_count += import_indeterminate_count; match import_indeterminate_count { 0 => self.determined_imports.push(import), @@ -475,7 +465,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { pub(crate) fn finalize_imports(&mut self) { for module in self.arenas.local_modules().iter() { - self.finalize_resolutions_in(module); + self.finalize_resolutions_in(*module); } let mut seen_spans = FxHashSet::default(); @@ -546,17 +536,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { pub(crate) fn check_hidden_glob_reexports( &mut self, - exported_ambiguities: FxHashSet<Interned<'a, NameBinding<'a>>>, + exported_ambiguities: FxHashSet<NameBinding<'a>>, ) { for module in self.arenas.local_modules().iter() { - for (key, resolution) in self.resolutions(module).borrow().iter() { + for (key, resolution) in self.resolutions(*module).borrow().iter() { let resolution = resolution.borrow(); if let Some(binding) = resolution.binding { if let NameBindingKind::Import { import, .. } = binding.kind && let Some((amb_binding, _)) = binding.ambiguity && binding.res() != Res::Err - && exported_ambiguities.contains(&Interned::new_unchecked(binding)) + && exported_ambiguities.contains(&binding) { self.lint_buffer.buffer_lint_with_diagnostic( AMBIGUOUS_GLOB_REEXPORTS, @@ -612,7 +602,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - fn throw_unresolved_import_error(&mut self, errors: Vec<(&Import<'_>, UnresolvedImportError)>) { + fn throw_unresolved_import_error(&mut self, errors: Vec<(Import<'_>, UnresolvedImportError)>) { if errors.is_empty() { return; } @@ -704,7 +694,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// /// Meanwhile, if resolve successful, the resolved bindings are written /// into the module. - fn resolve_import(&mut self, import: &'a Import<'a>) -> usize { + fn resolve_import(&mut self, import: Import<'a>) -> usize { debug!( "(resolving import for module) resolving import `{}::...` in `{}`", Segment::names_to_string(&import.module_path), @@ -784,7 +774,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } let key = BindingKey::new(target, ns); this.update_resolution(parent, key, |_, resolution| { - resolution.single_imports.remove(&Interned::new_unchecked(import)); + resolution.single_imports.remove(&import); }); } } @@ -798,7 +788,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// /// Optionally returns an unresolved import error. This error is buffered and used to /// consolidate multiple unresolved import errors into a single diagnostic. - fn finalize_import(&mut self, import: &'a Import<'a>) -> Option<UnresolvedImportError> { + fn finalize_import(&mut self, import: Import<'a>) -> Option<UnresolvedImportError> { let orig_vis = import.vis.take(); let ignore_binding = match &import.kind { ImportKind::Single { target_bindings, .. } => target_bindings[TypeNS].get(), @@ -824,7 +814,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { PathResult::Module(module) => { // Consistency checks, analogous to `finalize_macro_resolutions`. if let Some(initial_module) = import.imported_module.get() { - if !ModuleOrUniformRoot::same_def(module, initial_module) && no_ambiguity { + if module != initial_module && no_ambiguity { span_bug!(import.span, "inconsistent resolution for an import"); } } else if self.privacy_errors.is_empty() { @@ -926,7 +916,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } if let ModuleOrUniformRoot::Module(module) = module { - if ptr::eq(module, import.parent_scope.module) { + if module == import.parent_scope.module { // Importing a module into itself is not allowed. return Some(UnresolvedImportError { span: import.span, @@ -1242,9 +1232,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn check_for_redundant_imports( &mut self, ident: Ident, - import: &'a Import<'a>, - source_bindings: &PerNS<Cell<Result<&'a NameBinding<'a>, Determinacy>>>, - target_bindings: &PerNS<Cell<Option<&'a NameBinding<'a>>>>, + import: Import<'a>, + source_bindings: &PerNS<Cell<Result<NameBinding<'a>, Determinacy>>>, + target_bindings: &PerNS<Cell<Option<NameBinding<'a>>>>, target: Ident, ) { // This function is only called for single imports. @@ -1305,7 +1295,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - fn resolve_glob_import(&mut self, import: &'a Import<'a>) { + fn resolve_glob_import(&mut self, import: Import<'a>) { // This function is only called for glob imports. let ImportKind::Glob { id, is_prelude, .. } = import.kind else { unreachable!() }; @@ -1319,7 +1309,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if module.is_trait() { self.tcx.sess.create_err(ItemsInTraitsAreNotImportable { span: import.span }).emit(); return; - } else if ptr::eq(module, import.parent_scope.module) { + } else if module == import.parent_scope.module { return; } else if is_prelude { self.prelude = Some(module); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 744dcf0db84..90cb312edd2 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1284,7 +1284,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ident: Ident, ns: Namespace, finalize: Option<Finalize>, - ignore_binding: Option<&'a NameBinding<'a>>, + ignore_binding: Option<NameBinding<'a>>, ) -> Option<LexicalScopeBinding<'a>> { self.r.resolve_ident_in_lexical_scope( ident, @@ -2972,7 +2972,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { F: FnOnce(Ident, String, Option<Symbol>) -> ResolutionError<'a>, { // If there is a TraitRef in scope for an impl, then the method must be in the trait. - let Some((module, _)) = &self.current_trait_ref else { return; }; + let Some((module, _)) = self.current_trait_ref else { return; }; ident.span.normalize_to_macros_2_0_and_adjust(module.expansion); let key = BindingKey::new(ident, ns); let mut binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding); @@ -3503,7 +3503,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let report_errors = |this: &mut Self, res: Option<Res>| { if this.should_report_errs() { let (err, candidates) = - this.smart_resolve_report_errors(path, path_span, source, res); + this.smart_resolve_report_errors(path, path, path_span, source, res); let def_id = this.parent_scope.module.nearest_parent_mod(); let instead = res.is_some(); @@ -3560,8 +3560,13 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { _ => return Some(parent_err), }; - let (mut err, candidates) = - this.smart_resolve_report_errors(prefix_path, path_span, PathSource::Type, None); + let (mut err, candidates) = this.smart_resolve_report_errors( + prefix_path, + path, + path_span, + PathSource::Type, + None, + ); // There are two different error messages user might receive at // this point: diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index c62fc031a16..c0e3f1aaf01 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -4,6 +4,7 @@ use crate::late::{LifetimeBinderKind, LifetimeRes, LifetimeRibKind, LifetimeUseS use crate::{errors, path_names_to_string}; use crate::{Module, ModuleKind, ModuleOrUniformRoot}; use crate::{PathResult, PathSource, Segment}; +use rustc_hir::def::Namespace::{self, *}; use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt}; use rustc_ast::{ @@ -17,7 +18,6 @@ use rustc_errors::{ MultiSpan, }; use rustc_hir as hir; -use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; use rustc_hir::PrimTy; @@ -221,10 +221,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { let suggestion = if self.current_trait_ref.is_none() && let Some((fn_kind, _)) = self.diagnostic_metadata.current_function && let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt() + && let FnKind::Fn(_, _, sig, ..) = fn_kind && let Some(items) = self.diagnostic_metadata.current_impl_items && let Some(item) = items.iter().find(|i| { if let AssocItemKind::Fn(..) | AssocItemKind::Const(..) = &i.kind && i.ident.name == item_str.name + // don't suggest if the item is in Fn signature arguments + // issue #112590 + && !sig.span.contains(item_span) { debug!(?item_str.name); return true @@ -318,11 +322,56 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } } + /// Try to suggest for a module path that cannot be resolved. + /// Such as `fmt::Debug` where `fmt` is not resolved without importing, + /// here we search with `lookup_import_candidates` for a module named `fmt` + /// with `TypeNS` as namespace. + /// + /// We need a separate function here because we won't suggest for a path with single segment + /// and we won't change `SourcePath` api `is_expected` to match `Type` with `DefKind::Mod` + pub(crate) fn smart_resolve_partial_mod_path_errors( + &mut self, + prefix_path: &[Segment], + path: &[Segment], + ) -> Vec<ImportSuggestion> { + let next_seg = if path.len() >= prefix_path.len() + 1 && prefix_path.len() == 1 { + path.get(prefix_path.len()) + } else { + None + }; + if let Some(segment) = prefix_path.last() && + let Some(next_seg) = next_seg { + let candidates = self.r.lookup_import_candidates( + segment.ident, + Namespace::TypeNS, + &self.parent_scope, + &|res: Res| matches!(res, Res::Def(DefKind::Mod, _)), + ); + // double check next seg is valid + candidates + .into_iter() + .filter(|candidate| { + if let Some(def_id) = candidate.did && + let Some(module) = self.r.get_module(def_id) { + self.r.resolutions(module).borrow().iter().any(|(key, _r)| { + key.ident.name == next_seg.ident.name + }) + } else { + false + } + }) + .collect::<Vec<_>>() + } else { + Vec::new() + } + } + /// Handles error reporting for `smart_resolve_path_fragment` function. /// Creates base error and amends it with one short label and possibly some longer helps/notes. pub(crate) fn smart_resolve_report_errors( &mut self, path: &[Segment], + full_path: &[Segment], span: Span, source: PathSource<'_>, res: Option<Res>, @@ -364,7 +413,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } let (found, candidates) = - self.try_lookup_name_relaxed(&mut err, source, path, span, res, &base_error); + self.try_lookup_name_relaxed(&mut err, source, path, full_path, span, res, &base_error); if found { return (err, candidates); } @@ -470,6 +519,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { err: &mut Diagnostic, source: PathSource<'_>, path: &[Segment], + full_path: &[Segment], span: Span, res: Option<Res>, base_error: &BaseError, @@ -639,6 +689,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } } + if candidates.is_empty() { + candidates = self.smart_resolve_partial_mod_path_errors(path, full_path); + } + return (false, candidates); } @@ -1539,7 +1593,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { return None; } - let resolutions = self.r.resolutions(module); + let resolutions = self.r.resolutions(*module); let targets = resolutions .borrow() .iter() diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index cc4cb9fa30c..da3d86a4718 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -14,6 +14,7 @@ #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(never_type)] +#![feature(rustc_attrs)] #![recursion_limit = "256"] #![allow(rustdoc::private_intra_doc_links)] #![allow(rustc::potential_query_instability)] @@ -61,10 +62,10 @@ use rustc_span::{Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; use std::cell::{Cell, RefCell}; use std::collections::BTreeSet; -use std::{fmt, ptr}; +use std::fmt; use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion}; -use imports::{Import, ImportKind, NameResolution}; +use imports::{Import, ImportData, ImportKind, NameResolution}; use late::{HasGenericParams, PathSource, PatternSource}; use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; @@ -352,7 +353,7 @@ impl<'a> From<&'a ast::PathSegment> for Segment { /// forward. #[derive(Debug)] enum LexicalScopeBinding<'a> { - Item(&'a NameBinding<'a>), + Item(NameBinding<'a>), Res(Res), } @@ -365,7 +366,7 @@ impl<'a> LexicalScopeBinding<'a> { } } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] enum ModuleOrUniformRoot<'a> { /// Regular module. Module(Module<'a>), @@ -383,23 +384,6 @@ enum ModuleOrUniformRoot<'a> { CurrentScope, } -impl ModuleOrUniformRoot<'_> { - fn same_def(lhs: Self, rhs: Self) -> bool { - match (lhs, rhs) { - (ModuleOrUniformRoot::Module(lhs), ModuleOrUniformRoot::Module(rhs)) => { - ptr::eq(lhs, rhs) - } - ( - ModuleOrUniformRoot::CrateRootAndExternPrelude, - ModuleOrUniformRoot::CrateRootAndExternPrelude, - ) - | (ModuleOrUniformRoot::ExternPrelude, ModuleOrUniformRoot::ExternPrelude) - | (ModuleOrUniformRoot::CurrentScope, ModuleOrUniformRoot::CurrentScope) => true, - _ => false, - } - } -} - #[derive(Debug)] enum PathResult<'a> { Module(ModuleOrUniformRoot<'a>), @@ -518,11 +502,11 @@ struct ModuleData<'a> { /// Whether `#[no_implicit_prelude]` is active. no_implicit_prelude: bool, - glob_importers: RefCell<Vec<&'a Import<'a>>>, - globs: RefCell<Vec<&'a Import<'a>>>, + glob_importers: RefCell<Vec<Import<'a>>>, + globs: RefCell<Vec<Import<'a>>>, /// Used to memoize the traits in this module for faster searches through all traits in scope. - traits: RefCell<Option<Box<[(Ident, &'a NameBinding<'a>)]>>>, + traits: RefCell<Option<Box<[(Ident, NameBinding<'a>)]>>>, /// Span of the module itself. Used for error reporting. span: Span, @@ -530,7 +514,11 @@ struct ModuleData<'a> { expansion: ExpnId, } -type Module<'a> = &'a ModuleData<'a>; +/// All modules are unique and allocated on a same arena, +/// so we can use referential equality to compare them. +#[derive(Clone, Copy, PartialEq)] +#[rustc_pass_by_value] +struct Module<'a>(Interned<'a, ModuleData<'a>>); impl<'a> ModuleData<'a> { fn new( @@ -558,11 +546,13 @@ impl<'a> ModuleData<'a> { expansion, } } +} - fn for_each_child<'tcx, R, F>(&'a self, resolver: &mut R, mut f: F) +impl<'a> Module<'a> { + fn for_each_child<'tcx, R, F>(self, resolver: &mut R, mut f: F) where R: AsMut<Resolver<'a, 'tcx>>, - F: FnMut(&mut R, Ident, Namespace, &'a NameBinding<'a>), + F: FnMut(&mut R, Ident, Namespace, NameBinding<'a>), { for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() { if let Some(binding) = name_resolution.borrow().binding { @@ -572,7 +562,7 @@ impl<'a> ModuleData<'a> { } /// This modifies `self` in place. The traits will be stored in `self.traits`. - fn ensure_traits<'tcx, R>(&'a self, resolver: &mut R) + fn ensure_traits<'tcx, R>(self, resolver: &mut R) where R: AsMut<Resolver<'a, 'tcx>>, { @@ -591,7 +581,7 @@ impl<'a> ModuleData<'a> { } } - fn res(&self) -> Option<Res> { + fn res(self) -> Option<Res> { match self.kind { ModuleKind::Def(kind, def_id, _) => Some(Res::Def(kind, def_id)), _ => None, @@ -599,11 +589,11 @@ impl<'a> ModuleData<'a> { } // Public for rustdoc. - fn def_id(&self) -> DefId { + fn def_id(self) -> DefId { self.opt_def_id().expect("`ModuleData::def_id` is called on a block module") } - fn opt_def_id(&self) -> Option<DefId> { + fn opt_def_id(self) -> Option<DefId> { match self.kind { ModuleKind::Def(_, def_id, _) => Some(def_id), _ => None, @@ -611,15 +601,15 @@ impl<'a> ModuleData<'a> { } // `self` resolves to the first module ancestor that `is_normal`. - fn is_normal(&self) -> bool { + fn is_normal(self) -> bool { matches!(self.kind, ModuleKind::Def(DefKind::Mod, _, _)) } - fn is_trait(&self) -> bool { + fn is_trait(self) -> bool { matches!(self.kind, ModuleKind::Def(DefKind::Trait, _, _)) } - fn nearest_item_scope(&'a self) -> Module<'a> { + fn nearest_item_scope(self) -> Module<'a> { match self.kind { ModuleKind::Def(DefKind::Enum | DefKind::Trait, ..) => { self.parent.expect("enum or trait module without a parent") @@ -630,15 +620,15 @@ impl<'a> ModuleData<'a> { /// The [`DefId`] of the nearest `mod` item ancestor (which may be this module). /// This may be the crate root. - fn nearest_parent_mod(&self) -> DefId { + fn nearest_parent_mod(self) -> DefId { match self.kind { ModuleKind::Def(DefKind::Mod, def_id, _) => def_id, _ => self.parent.expect("non-root module without parent").nearest_parent_mod(), } } - fn is_ancestor_of(&self, mut other: &Self) -> bool { - while !ptr::eq(self, other) { + fn is_ancestor_of(self, mut other: Self) -> bool { + while self != other { if let Some(parent) = other.parent { other = parent; } else { @@ -649,7 +639,15 @@ impl<'a> ModuleData<'a> { } } -impl<'a> fmt::Debug for ModuleData<'a> { +impl<'a> std::ops::Deref for Module<'a> { + type Target = ModuleData<'a>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'a> fmt::Debug for Module<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self.res()) } @@ -657,20 +655,24 @@ impl<'a> fmt::Debug for ModuleData<'a> { /// Records a possibly-private value, type, or module definition. #[derive(Clone, Debug)] -struct NameBinding<'a> { +struct NameBindingData<'a> { kind: NameBindingKind<'a>, - ambiguity: Option<(&'a NameBinding<'a>, AmbiguityKind)>, + ambiguity: Option<(NameBinding<'a>, AmbiguityKind)>, expansion: LocalExpnId, span: Span, vis: ty::Visibility<DefId>, } +/// All name bindings are unique and allocated on a same arena, +/// so we can use referential equality to compare them. +type NameBinding<'a> = Interned<'a, NameBindingData<'a>>; + trait ToNameBinding<'a> { - fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a>; + fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> NameBinding<'a>; } -impl<'a> ToNameBinding<'a> for &'a NameBinding<'a> { - fn to_name_binding(self, _: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { +impl<'a> ToNameBinding<'a> for NameBinding<'a> { + fn to_name_binding(self, _: &'a ResolverArenas<'a>) -> NameBinding<'a> { self } } @@ -679,7 +681,7 @@ impl<'a> ToNameBinding<'a> for &'a NameBinding<'a> { enum NameBindingKind<'a> { Res(Res), Module(Module<'a>), - Import { binding: &'a NameBinding<'a>, import: &'a Import<'a>, used: Cell<bool> }, + Import { binding: NameBinding<'a>, import: Import<'a>, used: Cell<bool> }, } impl<'a> NameBindingKind<'a> { @@ -692,7 +694,7 @@ impl<'a> NameBindingKind<'a> { #[derive(Debug)] struct PrivacyError<'a> { ident: Ident, - binding: &'a NameBinding<'a>, + binding: NameBinding<'a>, dedup_span: Span, outermost_res: Option<(Res, Ident)>, parent_scope: ParentScope<'a>, @@ -761,13 +763,13 @@ enum AmbiguityErrorMisc { struct AmbiguityError<'a> { kind: AmbiguityKind, ident: Ident, - b1: &'a NameBinding<'a>, - b2: &'a NameBinding<'a>, + b1: NameBinding<'a>, + b2: NameBinding<'a>, misc1: AmbiguityErrorMisc, misc2: AmbiguityErrorMisc, } -impl<'a> NameBinding<'a> { +impl<'a> NameBindingData<'a> { fn module(&self) -> Option<Module<'a>> { match self.kind { NameBindingKind::Module(module) => Some(module), @@ -805,14 +807,12 @@ impl<'a> NameBinding<'a> { fn is_extern_crate(&self) -> bool { match self.kind { - NameBindingKind::Import { - import: &Import { kind: ImportKind::ExternCrate { .. }, .. }, - .. - } => true, - NameBindingKind::Module(&ModuleData { - kind: ModuleKind::Def(DefKind::Mod, def_id, _), - .. - }) => def_id.is_crate_root(), + NameBindingKind::Import { import, .. } => { + matches!(import.kind, ImportKind::ExternCrate { .. }) + } + NameBindingKind::Module(module) + if let ModuleKind::Def(DefKind::Mod, def_id, _) = module.kind + => def_id.is_crate_root(), _ => false, } } @@ -855,7 +855,7 @@ impl<'a> NameBinding<'a> { fn may_appear_after( &self, invoc_parent_expansion: LocalExpnId, - binding: &NameBinding<'_>, + binding: NameBinding<'_>, ) -> bool { // self > max(invoc, binding) => !(self <= invoc || self <= binding) // Expansions are partially ordered, so "may appear after" is an inversion of @@ -872,7 +872,7 @@ impl<'a> NameBinding<'a> { #[derive(Default, Clone)] struct ExternPreludeEntry<'a> { - extern_crate_item: Option<&'a NameBinding<'a>>, + extern_crate_item: Option<NameBinding<'a>>, introduced_by_item: bool, } @@ -917,10 +917,10 @@ pub struct Resolver<'a, 'tcx> { field_visibility_spans: FxHashMap<DefId, Vec<Span>>, /// All imports known to succeed or fail. - determined_imports: Vec<&'a Import<'a>>, + determined_imports: Vec<Import<'a>>, /// All non-determined imports. - indeterminate_imports: Vec<&'a Import<'a>>, + indeterminate_imports: Vec<Import<'a>>, // Spans for local variables found during pattern resolution. // Used for suggestions during error reporting. @@ -962,7 +962,7 @@ pub struct Resolver<'a, 'tcx> { /// language items. empty_module: Module<'a>, module_map: FxHashMap<DefId, Module<'a>>, - binding_parent_modules: FxHashMap<Interned<'a, NameBinding<'a>>, Module<'a>>, + binding_parent_modules: FxHashMap<NameBinding<'a>, Module<'a>>, underscore_disambiguator: u32, @@ -984,7 +984,7 @@ pub struct Resolver<'a, 'tcx> { macro_expanded_macro_export_errors: BTreeSet<(Span, Span)>, arenas: &'a ResolverArenas<'a>, - dummy_binding: &'a NameBinding<'a>, + dummy_binding: NameBinding<'a>, used_extern_options: FxHashSet<Symbol>, macro_names: FxHashSet<Ident>, @@ -993,7 +993,7 @@ pub struct Resolver<'a, 'tcx> { /// the surface (`macro` items in libcore), but are actually attributes or derives. builtin_macro_kinds: FxHashMap<LocalDefId, MacroKind>, registered_tools: &'tcx RegisteredTools, - macro_use_prelude: FxHashMap<Symbol, &'a NameBinding<'a>>, + macro_use_prelude: FxHashMap<Symbol, NameBinding<'a>>, macro_map: FxHashMap<DefId, MacroData>, dummy_ext_bang: Lrc<SyntaxExtension>, dummy_ext_derive: Lrc<SyntaxExtension>, @@ -1005,7 +1005,7 @@ pub struct Resolver<'a, 'tcx> { proc_macro_stubs: FxHashSet<LocalDefId>, /// Traces collected during macro resolution and validated when it's complete. single_segment_macro_resolutions: - Vec<(Ident, MacroKind, ParentScope<'a>, Option<&'a NameBinding<'a>>)>, + Vec<(Ident, MacroKind, ParentScope<'a>, Option<NameBinding<'a>>)>, multi_segment_macro_resolutions: Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'a>, Option<Res>)>, builtin_attrs: Vec<(Ident, ParentScope<'a>)>, @@ -1030,7 +1030,7 @@ pub struct Resolver<'a, 'tcx> { /// Avoid duplicated errors for "name already defined". name_already_seen: FxHashMap<Symbol, Span>, - potentially_unused_imports: Vec<&'a Import<'a>>, + potentially_unused_imports: Vec<Import<'a>>, /// Table for mapping struct IDs into struct constructor IDs, /// it's not used during normal resolution, only for better error reporting. @@ -1085,7 +1085,7 @@ pub struct Resolver<'a, 'tcx> { pub struct ResolverArenas<'a> { modules: TypedArena<ModuleData<'a>>, local_modules: RefCell<Vec<Module<'a>>>, - imports: TypedArena<Import<'a>>, + imports: TypedArena<ImportData<'a>>, name_resolutions: TypedArena<RefCell<NameResolution<'a>>>, ast_paths: TypedArena<ast::Path>, dropless: DroplessArena, @@ -1101,8 +1101,13 @@ impl<'a> ResolverArenas<'a> { no_implicit_prelude: bool, module_map: &mut FxHashMap<DefId, Module<'a>>, ) -> Module<'a> { - let module = - self.modules.alloc(ModuleData::new(parent, kind, expn_id, span, no_implicit_prelude)); + let module = Module(Interned::new_unchecked(self.modules.alloc(ModuleData::new( + parent, + kind, + expn_id, + span, + no_implicit_prelude, + )))); let def_id = module.opt_def_id(); if def_id.map_or(true, |def_id| def_id.is_local()) { self.local_modules.borrow_mut().push(module); @@ -1115,11 +1120,11 @@ impl<'a> ResolverArenas<'a> { fn local_modules(&'a self) -> std::cell::Ref<'a, Vec<Module<'a>>> { self.local_modules.borrow() } - fn alloc_name_binding(&'a self, name_binding: NameBinding<'a>) -> &'a NameBinding<'a> { - self.dropless.alloc(name_binding) + fn alloc_name_binding(&'a self, name_binding: NameBindingData<'a>) -> NameBinding<'a> { + Interned::new_unchecked(self.dropless.alloc(name_binding)) } - fn alloc_import(&'a self, import: Import<'a>) -> &'a Import<'_> { - self.imports.alloc(import) + fn alloc_import(&'a self, import: ImportData<'a>) -> Import<'a> { + Interned::new_unchecked(self.imports.alloc(import)) } fn alloc_name_resolution(&'a self) -> &'a RefCell<NameResolution<'a>> { self.name_resolutions.alloc(Default::default()) @@ -1314,7 +1319,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { macro_expanded_macro_export_errors: BTreeSet::new(), arenas, - dummy_binding: arenas.alloc_name_binding(NameBinding { + dummy_binding: arenas.alloc_name_binding(NameBindingData { kind: NameBindingKind::Res(Res::Err), ambiguity: None, expansion: LocalExpnId::ROOT, @@ -1624,7 +1629,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.maybe_unused_trait_imports.insert(def_id); import_ids.push(def_id); } - self.add_to_glob_map(&import, trait_name); + self.add_to_glob_map(*import, trait_name); kind = &binding.kind; } import_ids @@ -1646,7 +1651,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { module.populate_on_access.set(false); self.build_reduced_graph_external(module); } - &module.lazy_resolutions + &module.0.0.lazy_resolutions } fn resolution( @@ -1679,12 +1684,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { false } - fn record_use( - &mut self, - ident: Ident, - used_binding: &'a NameBinding<'a>, - is_lexical_scope: bool, - ) { + fn record_use(&mut self, ident: Ident, used_binding: NameBinding<'a>, is_lexical_scope: bool) { if let Some((b2, kind)) = used_binding.ambiguity { let ambiguity_error = AmbiguityError { kind, @@ -1704,10 +1704,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // but not introduce it, as used if they are accessed from lexical scope. if is_lexical_scope { if let Some(entry) = self.extern_prelude.get(&ident.normalize_to_macros_2_0()) { - if let Some(crate_item) = entry.extern_crate_item { - if ptr::eq(used_binding, crate_item) && !entry.introduced_by_item { - return; - } + if !entry.introduced_by_item && entry.extern_crate_item == Some(used_binding) { + return; } } } @@ -1716,13 +1714,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if let Some(id) = import.id() { self.used_imports.insert(id); } - self.add_to_glob_map(&import, ident); + self.add_to_glob_map(import, ident); self.record_use(ident, binding, false); } } #[inline] - fn add_to_glob_map(&mut self, import: &Import<'_>, ident: Ident) { + fn add_to_glob_map(&mut self, import: Import<'_>, ident: Ident) { if let ImportKind::Glob { id, .. } = import.kind { let def_id = self.local_def_id(id); self.glob_map.entry(def_id).or_default().insert(ident.name); @@ -1831,11 +1829,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { vis.is_accessible_from(module.nearest_parent_mod(), self.tcx) } - fn set_binding_parent_module(&mut self, binding: &'a NameBinding<'a>, module: Module<'a>) { - if let Some(old_module) = - self.binding_parent_modules.insert(Interned::new_unchecked(binding), module) - { - if !ptr::eq(module, old_module) { + fn set_binding_parent_module(&mut self, binding: NameBinding<'a>, module: Module<'a>) { + if let Some(old_module) = self.binding_parent_modules.insert(binding, module) { + if module != old_module { span_bug!(binding.span, "parent module is reset for binding"); } } @@ -1843,25 +1839,25 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn disambiguate_macro_rules_vs_modularized( &self, - macro_rules: &'a NameBinding<'a>, - modularized: &'a NameBinding<'a>, + macro_rules: NameBinding<'a>, + modularized: NameBinding<'a>, ) -> bool { // Some non-controversial subset of ambiguities "modularized macro name" vs "macro_rules" // is disambiguated to mitigate regressions from macro modularization. // Scoping for `macro_rules` behaves like scoping for `let` at module level, in general. match ( - self.binding_parent_modules.get(&Interned::new_unchecked(macro_rules)), - self.binding_parent_modules.get(&Interned::new_unchecked(modularized)), + self.binding_parent_modules.get(¯o_rules), + self.binding_parent_modules.get(&modularized), ) { (Some(macro_rules), Some(modularized)) => { macro_rules.nearest_parent_mod() == modularized.nearest_parent_mod() - && modularized.is_ancestor_of(macro_rules) + && modularized.is_ancestor_of(*macro_rules) } _ => false, } } - fn extern_prelude_get(&mut self, ident: Ident, finalize: bool) -> Option<&'a NameBinding<'a>> { + fn extern_prelude_get(&mut self, ident: Ident, finalize: bool) -> Option<NameBinding<'a>> { if ident.is_path_segment_keyword() { // Make sure `self`, `super` etc produce an error when passed to here. return None; diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index d33e8d40b63..d16b7902f60 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -42,7 +42,7 @@ type Res = def::Res<NodeId>; /// Not modularized, can shadow previous `macro_rules` bindings, etc. #[derive(Debug)] pub(crate) struct MacroRulesBinding<'a> { - pub(crate) binding: &'a NameBinding<'a>, + pub(crate) binding: NameBinding<'a>, /// `macro_rules` scope into which the `macro_rules` item was planted. pub(crate) parent_macro_rules_scope: MacroRulesScopeRef<'a>, pub(crate) ident: Ident, @@ -870,7 +870,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn prohibit_imported_non_macro_attrs( &self, - binding: Option<&'a NameBinding<'a>>, + binding: Option<NameBinding<'a>>, res: Option<Res>, span: Span, ) { diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml index 6046780685a..46b923e8c7b 100644 --- a/compiler/rustc_serialize/Cargo.toml +++ b/compiler/rustc_serialize/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" edition = "2021" [dependencies] -indexmap = "1.9.3" +indexmap = "2.0.0" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2.12" diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 2fe7a6f511b..f97cb3440d2 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -737,14 +737,20 @@ pub enum PrintRequest { pub enum TraitSolver { /// Classic trait solver in `rustc_trait_selection::traits::select` Classic, - /// Chalk trait solver - Chalk, /// Experimental trait solver in `rustc_trait_selection::solve` Next, /// Use the new trait solver during coherence NextCoherence, } +#[derive(Default, Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum DumpSolverProofTree { + Always, + OnError, + #[default] + Never, +} + pub enum Input { /// Load source code from a file. File(PathBuf), @@ -1021,6 +1027,7 @@ impl Default for Options { json_future_incompat: false, pretty: None, working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()), + color: ColorConfig::Auto, } } } @@ -2801,6 +2808,7 @@ pub fn build_session_options( json_future_incompat, pretty, working_dir, + color, } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 16a4c2a8b3d..7840a0ecf0b 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -4,6 +4,7 @@ use crate::search_paths::SearchPath; use crate::utils::NativeLib; use crate::{lint, EarlyErrorHandler}; use rustc_data_structures::profiling::TimePassesFormat; +use rustc_errors::ColorConfig; use rustc_errors::{LanguageIdentifier, TerminalUrl}; use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet}; use rustc_target::spec::{ @@ -212,6 +213,7 @@ top_level_options!( /// The (potentially remapped) working directory working_dir: RealFileName [TRACKED], + color: ColorConfig [UNTRACKED], } ); @@ -386,7 +388,7 @@ mod desc { pub const parse_unpretty: &str = "`string` or `string=string`"; pub const parse_treat_err_as_bug: &str = "either no value or a number bigger than 0"; pub const parse_trait_solver: &str = - "one of the supported solver modes (`classic`, `chalk`, or `next`)"; + "one of the supported solver modes (`classic`, `next`, or `next-coherence`)"; pub const parse_lto: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted"; pub const parse_linker_plugin_lto: &str = @@ -418,6 +420,7 @@ mod desc { "a `,` separated combination of `bti`, `b-key`, `pac-ret`, or `leaf`"; pub const parse_proc_macro_execution_strategy: &str = "one of supported execution strategies (`same-thread`, or `cross-thread`)"; + pub const parse_dump_solver_proof_tree: &str = "one of: `always`, `on-request`, `on-error`"; } mod parse { @@ -983,7 +986,6 @@ mod parse { pub(crate) fn parse_trait_solver(slot: &mut TraitSolver, v: Option<&str>) -> bool { match v { Some("classic") => *slot = TraitSolver::Classic, - Some("chalk") => *slot = TraitSolver::Chalk, Some("next") => *slot = TraitSolver::Next, Some("next-coherence") => *slot = TraitSolver::NextCoherence, // default trait solver is subject to change.. @@ -1238,6 +1240,19 @@ mod parse { }; true } + + pub(crate) fn parse_dump_solver_proof_tree( + slot: &mut DumpSolverProofTree, + v: Option<&str>, + ) -> bool { + match v { + None | Some("always") => *slot = DumpSolverProofTree::Always, + Some("never") => *slot = DumpSolverProofTree::Never, + Some("on-error") => *slot = DumpSolverProofTree::OnError, + _ => return false, + }; + true + } } options! { @@ -1463,8 +1478,11 @@ options! { "output statistics about monomorphization collection"), dump_mono_stats_format: DumpMonoStatsFormat = (DumpMonoStatsFormat::Markdown, parse_dump_mono_stats, [UNTRACKED], "the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)"), - dump_solver_proof_tree: bool = (false, parse_bool, [UNTRACKED], - "dump a proof tree for every goal evaluated by the new trait solver"), + dump_solver_proof_tree: DumpSolverProofTree = (DumpSolverProofTree::Never, parse_dump_solver_proof_tree, [UNTRACKED], + "dump a proof tree for every goal evaluated by the new trait solver. If the flag is specified without any options after it + then it defaults to `always`. If the flag is not specified at all it defaults to `on-request`."), + dump_solver_proof_tree_use_cache: Option<bool> = (None, parse_opt_bool, [UNTRACKED], + "determines whether dumped proof trees use the global cache"), dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED], "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"), dylib_lto: bool = (false, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_smir/Cargo.toml b/compiler/rustc_smir/Cargo.toml index 80360a3c73f..a6e6de5f785 100644 --- a/compiler/rustc_smir/Cargo.toml +++ b/compiler/rustc_smir/Cargo.toml @@ -8,6 +8,7 @@ rustc_hir = { path = "../rustc_hir" } rustc_middle = { path = "../rustc_middle", optional = true } rustc_span = { path = "../rustc_span", optional = true } tracing = "0.1" +scoped-tls = "1.0" [features] default = [ diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs index b00f0a1c153..fb03633b99b 100644 --- a/compiler/rustc_smir/src/lib.rs +++ b/compiler/rustc_smir/src/lib.rs @@ -19,3 +19,6 @@ pub mod stable_mir; // Make this module private for now since external users should not call these directly. mod rustc_smir; + +#[macro_use] +extern crate scoped_tls; diff --git a/compiler/rustc_smir/src/stable_mir/mod.rs b/compiler/rustc_smir/src/stable_mir/mod.rs index 612777b9c75..5e599a77bcd 100644 --- a/compiler/rustc_smir/src/stable_mir/mod.rs +++ b/compiler/rustc_smir/src/stable_mir/mod.rs @@ -100,18 +100,17 @@ pub trait Context { fn rustc_tables(&mut self, f: &mut dyn FnMut(&mut Tables<'_>)); } -thread_local! { - /// A thread local variable that stores a pointer to the tables mapping between TyCtxt - /// datastructures and stable MIR datastructures. - static TLV: Cell<*mut ()> = const { Cell::new(std::ptr::null_mut()) }; -} +// A thread local variable that stores a pointer to the tables mapping between TyCtxt +// datastructures and stable MIR datastructures +scoped_thread_local! (static TLV: Cell<*mut ()>); pub fn run(mut context: impl Context, f: impl FnOnce()) { - assert!(TLV.get().is_null()); + assert!(!TLV.is_set()); fn g<'a>(mut context: &mut (dyn Context + 'a), f: impl FnOnce()) { - TLV.set(&mut context as *mut &mut _ as _); - f(); - TLV.replace(std::ptr::null_mut()); + let ptr: *mut () = &mut context as *mut &mut _ as _; + TLV.set(&Cell::new(ptr), || { + f(); + }); } g(&mut context, f); } @@ -119,9 +118,10 @@ pub fn run(mut context: impl Context, f: impl FnOnce()) { /// Loads the current context and calls a function with it. /// Do not nest these, as that will ICE. pub(crate) fn with<R>(f: impl FnOnce(&mut dyn Context) -> R) -> R { - let ptr = TLV.replace(std::ptr::null_mut()) as *mut &mut dyn Context; - assert!(!ptr.is_null()); - let ret = f(unsafe { *ptr }); - TLV.set(ptr as _); - ret + assert!(TLV.is_set()); + TLV.with(|tlv| { + let ptr = tlv.get(); + assert!(!ptr.is_null()); + f(unsafe { *(ptr as *mut &mut dyn Context) }) + }) } diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index a7c7575f392..ee93f74e750 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -18,4 +18,4 @@ tracing = "0.1" sha1 = "0.10.0" sha2 = "0.10.1" md5 = { package = "md-5", version = "0.10.0" } -indexmap = { version = "1.9.3" } +indexmap = { version = "2.0.0" } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index c58d85b99f7..66a627d5aac 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -656,6 +656,7 @@ symbols! { dyn_trait, e, edition_panic, + effects, eh_catch_typeinfo, eh_personality, emit, @@ -793,6 +794,7 @@ symbols! { hexagon_target_feature, hidden, homogeneous_aggregate, + host, html_favicon_url, html_logo_url, html_no_source, @@ -1284,6 +1286,7 @@ symbols! { rustc_evaluate_where_clauses, rustc_expected_cgu_reuse, rustc_has_incoherent_inherent_impls, + rustc_host, rustc_if_this_changed, rustc_inherit_overflow_checks, rustc_insignificant_dtor, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 254ede4e6a0..ec7032cd3bf 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -230,7 +230,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> { self.write_str("[")?; self = self.print_type(ty)?; self.write_str("; ")?; - if let Some(size) = size.kind().try_to_bits(self.tcx().data_layout.pointer_size) { + if let Some(size) = size.try_to_bits(self.tcx().data_layout.pointer_size) { write!(self, "{size}")? } else if let ty::ConstKind::Param(param) = size.kind() { self = param.print(self)? diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 85825513ce9..3b46275ec41 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -112,7 +112,7 @@ fn encode_const<'tcx>( let _ = write!(s, "{value}"); } - if let Some(scalar_int) = c.kind().try_to_scalar_int() { + if let Some(scalar_int) = c.try_to_scalar_int() { let signed = c.ty().is_signed(); match scalar_int.size().bits() { 8 if signed => push_signed_value(&mut s, scalar_int.try_to_i8().unwrap(), 0), @@ -504,8 +504,7 @@ fn encode_ty<'tcx>( let _ = write!( s, "{}", - &len.kind() - .try_to_scalar() + &len.try_to_scalar() .unwrap() .to_u64() .unwrap_or_else(|_| panic!("failed to convert length to u64")) @@ -644,7 +643,7 @@ fn encode_ty<'tcx>( s.push_str("u3refI"); s.push_str(&encode_ty(tcx, *ty0, dict, options)); s.push('E'); - compress(dict, DictKey::Ty(tcx.mk_imm_ref(*region, *ty0), TyQ::None), &mut s); + compress(dict, DictKey::Ty(Ty::new_imm_ref(tcx, *region, *ty0), TyQ::None), &mut s); if ty.is_mutable_ptr() { s = format!("{}{}", "U3mut", &s); compress(dict, DictKey::Ty(ty, TyQ::Mut), &mut s); @@ -740,7 +739,7 @@ fn transform_substs<'tcx>( options: TransformTyOptions, ) -> SubstsRef<'tcx> { let substs = substs.iter().map(|subst| match subst.unpack() { - GenericArgKind::Type(ty) if ty.is_c_void(tcx) => tcx.mk_unit().into(), + GenericArgKind::Type(ty) if ty.is_c_void(tcx) => Ty::new_unit(tcx).into(), GenericArgKind::Type(ty) => transform_ty(tcx, ty, options).into(), _ => subst, }); @@ -810,29 +809,28 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio _ if ty.is_unit() => {} ty::Tuple(tys) => { - ty = tcx.mk_tup_from_iter(tys.iter().map(|ty| transform_ty(tcx, ty, options))); + ty = Ty::new_tup_from_iter(tcx, tys.iter().map(|ty| transform_ty(tcx, ty, options))); } ty::Array(ty0, len) => { let len = len - .kind() .try_to_scalar() .unwrap() .to_u64() .unwrap_or_else(|_| panic!("failed to convert length to u64")); - ty = tcx.mk_array(transform_ty(tcx, *ty0, options), len); + ty = Ty::new_array(tcx, transform_ty(tcx, *ty0, options), len); } ty::Slice(ty0) => { - ty = tcx.mk_slice(transform_ty(tcx, *ty0, options)); + ty = Ty::new_slice(tcx, transform_ty(tcx, *ty0, options)); } ty::Adt(adt_def, substs) => { if ty.is_c_void(tcx) { - ty = tcx.mk_unit(); + ty = Ty::new_unit(tcx); } else if options.contains(TransformTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() { - ty = tcx.mk_adt(*adt_def, ty::List::empty()); + ty = Ty::new_adt(tcx, *adt_def, ty::List::empty()); } else if adt_def.repr().transparent() && adt_def.is_struct() { // Don't transform repr(transparent) types with an user-defined CFI encoding to // preserve the user-defined CFI encoding. @@ -863,37 +861,42 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio } } else { // Transform repr(transparent) types without non-ZST field into () - ty = tcx.mk_unit(); + ty = Ty::new_unit(tcx); } } else { - ty = tcx.mk_adt(*adt_def, transform_substs(tcx, substs, options)); + ty = Ty::new_adt(tcx, *adt_def, transform_substs(tcx, substs, options)); } } ty::FnDef(def_id, substs) => { - ty = tcx.mk_fn_def(*def_id, transform_substs(tcx, substs, options)); + ty = Ty::new_fn_def(tcx, *def_id, transform_substs(tcx, substs, options)); } ty::Closure(def_id, substs) => { - ty = tcx.mk_closure(*def_id, transform_substs(tcx, substs, options)); + ty = Ty::new_closure(tcx, *def_id, transform_substs(tcx, substs, options)); } ty::Generator(def_id, substs, movability) => { - ty = tcx.mk_generator(*def_id, transform_substs(tcx, substs, options), *movability); + ty = Ty::new_generator( + tcx, + *def_id, + transform_substs(tcx, substs, options), + *movability, + ); } ty::Ref(region, ty0, ..) => { if options.contains(TransformTyOptions::GENERALIZE_POINTERS) { if ty.is_mutable_ptr() { - ty = tcx.mk_mut_ref(tcx.lifetimes.re_static, tcx.mk_unit()); + ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_static, Ty::new_unit(tcx)); } else { - ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_unit()); + ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_unit(tcx)); } } else { if ty.is_mutable_ptr() { - ty = tcx.mk_mut_ref(*region, transform_ty(tcx, *ty0, options)); + ty = Ty::new_mut_ref(tcx, *region, transform_ty(tcx, *ty0, options)); } else { - ty = tcx.mk_imm_ref(*region, transform_ty(tcx, *ty0, options)); + ty = Ty::new_imm_ref(tcx, *region, transform_ty(tcx, *ty0, options)); } } } @@ -901,22 +904,22 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio ty::RawPtr(tm) => { if options.contains(TransformTyOptions::GENERALIZE_POINTERS) { if ty.is_mutable_ptr() { - ty = tcx.mk_mut_ptr(tcx.mk_unit()); + ty = Ty::new_mut_ptr(tcx, Ty::new_unit(tcx)); } else { - ty = tcx.mk_imm_ptr(tcx.mk_unit()); + ty = Ty::new_imm_ptr(tcx, Ty::new_unit(tcx)); } } else { if ty.is_mutable_ptr() { - ty = tcx.mk_mut_ptr(transform_ty(tcx, tm.ty, options)); + ty = Ty::new_mut_ptr(tcx, transform_ty(tcx, tm.ty, options)); } else { - ty = tcx.mk_imm_ptr(transform_ty(tcx, tm.ty, options)); + ty = Ty::new_imm_ptr(tcx, transform_ty(tcx, tm.ty, options)); } } } ty::FnPtr(fn_sig) => { if options.contains(TransformTyOptions::GENERALIZE_POINTERS) { - ty = tcx.mk_imm_ptr(tcx.mk_unit()); + ty = Ty::new_imm_ptr(tcx, Ty::new_unit(tcx)); } else { let parameters: Vec<Ty<'tcx>> = fn_sig .skip_binder() @@ -925,21 +928,25 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio .map(|ty| transform_ty(tcx, *ty, options)) .collect(); let output = transform_ty(tcx, fn_sig.skip_binder().output(), options); - ty = tcx.mk_fn_ptr(ty::Binder::bind_with_vars( - tcx.mk_fn_sig( - parameters, - output, - fn_sig.c_variadic(), - fn_sig.unsafety(), - fn_sig.abi(), + ty = Ty::new_fn_ptr( + tcx, + ty::Binder::bind_with_vars( + tcx.mk_fn_sig( + parameters, + output, + fn_sig.c_variadic(), + fn_sig.unsafety(), + fn_sig.abi(), + ), + fn_sig.bound_vars(), ), - fn_sig.bound_vars(), - )); + ); } } ty::Dynamic(predicates, _region, kind) => { - ty = tcx.mk_dynamic( + ty = Ty::new_dynamic( + tcx, transform_predicates(tcx, predicates, options), tcx.lifetimes.re_erased, *kind, @@ -1108,14 +1115,16 @@ pub fn typeid_for_instance<'tcx>( )]); // Is the concrete self mutable? let self_ty = if fn_abi.args[0].layout.ty.is_mutable_ptr() { - tcx.mk_mut_ref( + Ty::new_mut_ref( + tcx, tcx.lifetimes.re_erased, - tcx.mk_dynamic(existential_predicates, tcx.lifetimes.re_erased, ty::Dyn), + Ty::new_dynamic(tcx, existential_predicates, tcx.lifetimes.re_erased, ty::Dyn), ) } else { - tcx.mk_imm_ref( + Ty::new_imm_ref( + tcx, tcx.lifetimes.re_erased, - tcx.mk_dynamic(existential_predicates, tcx.lifetimes.re_erased, ty::Dyn), + Ty::new_dynamic(tcx, existential_predicates, tcx.lifetimes.re_erased, ty::Dyn), ) }; diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 5dc00e31786..5e5cc6e4e4a 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -535,7 +535,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { match predicate.as_ref().skip_binder() { ty::ExistentialPredicate::Trait(trait_ref) => { // Use a type that can't appear in defaults of type parameters. - let dummy_self = cx.tcx.mk_fresh_ty(0); + let dummy_self = Ty::new_fresh(cx.tcx, 0); let trait_ref = trait_ref.with_self_ty(cx.tcx, dummy_self); cx = cx.print_def_path(trait_ref.def_id, trait_ref.substs)?; } @@ -651,7 +651,8 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { .builtin_deref(true) .expect("tried to dereference on non-ptr type") .ty; - let dereferenced_const = self.tcx.mk_const(ct.kind(), pointee_ty); + // FIXME(const_generics): add an assert that we only do this for valtrees. + let dereferenced_const = self.tcx.mk_ct_from_kind(ct.kind(), pointee_ty); self = dereferenced_const.print(self)?; } } diff --git a/compiler/rustc_target/src/abi/call/x86_64.rs b/compiler/rustc_target/src/abi/call/x86_64.rs index 74ef53915c9..b1aefaf0507 100644 --- a/compiler/rustc_target/src/abi/call/x86_64.rs +++ b/compiler/rustc_target/src/abi/call/x86_64.rs @@ -153,9 +153,9 @@ fn reg_component(cls: &[Option<Class>], i: &mut usize, size: Size) -> Option<Reg } } -fn cast_target(cls: &[Option<Class>], size: Size) -> CastTarget { +fn cast_target(cls: &[Option<Class>], size: Size) -> Option<CastTarget> { let mut i = 0; - let lo = reg_component(cls, &mut i, size).unwrap(); + let lo = reg_component(cls, &mut i, size)?; let offset = Size::from_bytes(8) * (i as u64); let mut target = CastTarget::from(lo); if size > offset { @@ -164,7 +164,7 @@ fn cast_target(cls: &[Option<Class>], size: Size) -> CastTarget { } } assert_eq!(reg_component(cls, &mut i, Size::ZERO), None); - target + Some(target) } const MAX_INT_REGS: usize = 6; // RDI, RSI, RDX, RCX, R8, R9 @@ -227,7 +227,9 @@ where // split into sized chunks passed individually if arg.layout.is_aggregate() { let size = arg.layout.size; - arg.cast_to(cast_target(cls, size)) + if let Some(cast_target) = cast_target(cls, size) { + arg.cast_to(cast_target); + } } else { arg.extend_integer_width_to(32); } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 2e5bb3db886..2365dfaf1af 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1325,6 +1325,7 @@ supported_targets! { ("armv7-unknown-netbsd-eabihf", armv7_unknown_netbsd_eabihf), ("i686-unknown-netbsd", i686_unknown_netbsd), ("powerpc-unknown-netbsd", powerpc_unknown_netbsd), + ("riscv64gc-unknown-netbsd", riscv64gc_unknown_netbsd), ("sparc64-unknown-netbsd", sparc64_unknown_netbsd), ("x86_64-unknown-netbsd", x86_64_unknown_netbsd), diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_netbsd.rs new file mode 100644 index 00000000000..a89bd363a47 --- /dev/null +++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_netbsd.rs @@ -0,0 +1,19 @@ +use crate::spec::{CodeModel, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + llvm_target: "riscv64-unknown-netbsd".into(), + pointer_width: 64, + data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), + arch: "riscv64".into(), + options: TargetOptions { + code_model: Some(CodeModel::Medium), + cpu: "generic-rv64".into(), + features: "+m,+a,+f,+d,+c".into(), + llvm_abiname: "lp64d".into(), + max_atomic_width: Some(64), + mcount: "__mcount".into(), + ..super::netbsd_base::opts() + }, + } +} diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs index ca7fcfd8ca1..422a6ee3442 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs @@ -1,6 +1,5 @@ use super::{EvalCtxt, SolverMode}; use rustc_infer::traits::query::NoSolution; -use rustc_middle::traits::solve::inspect::CandidateKind; use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; use rustc_middle::ty; @@ -110,12 +109,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { direction: ty::AliasRelationDirection, invert: Invert, ) -> QueryResult<'tcx> { - self.probe(|r| CandidateKind::Candidate { name: "normalizes-to".into(), result: *r }).enter( - |ecx| { - ecx.normalizes_to_inner(param_env, alias, other, direction, invert)?; - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }, - ) + self.probe_candidate("normalizes-to").enter(|ecx| { + ecx.normalizes_to_inner(param_env, alias, other, direction, invert)?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } fn normalizes_to_inner( @@ -156,20 +153,18 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { alias_rhs: ty::AliasTy<'tcx>, direction: ty::AliasRelationDirection, ) -> QueryResult<'tcx> { - self.probe(|r| CandidateKind::Candidate { name: "substs relate".into(), result: *r }).enter( - |ecx| { - match direction { - ty::AliasRelationDirection::Equate => { - ecx.eq(param_env, alias_lhs, alias_rhs)?; - } - ty::AliasRelationDirection::Subtype => { - ecx.sub(param_env, alias_lhs, alias_rhs)?; - } + self.probe_candidate("substs relate").enter(|ecx| { + match direction { + ty::AliasRelationDirection::Equate => { + ecx.eq(param_env, alias_lhs, alias_rhs)?; + } + ty::AliasRelationDirection::Subtype => { + ecx.sub(param_env, alias_lhs, alias_rhs)?; } + } - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }, - ) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } fn assemble_bidirectional_normalizes_to_candidate( @@ -179,23 +174,22 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { rhs: ty::Term<'tcx>, direction: ty::AliasRelationDirection, ) -> QueryResult<'tcx> { - self.probe(|r| CandidateKind::Candidate { name: "bidir normalizes-to".into(), result: *r }) - .enter(|ecx| { - ecx.normalizes_to_inner( - param_env, - lhs.to_alias_ty(ecx.tcx()).unwrap(), - rhs, - direction, - Invert::No, - )?; - ecx.normalizes_to_inner( - param_env, - rhs.to_alias_ty(ecx.tcx()).unwrap(), - lhs, - direction, - Invert::Yes, - )?; - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) + self.probe_candidate("bidir normalizes-to").enter(|ecx| { + ecx.normalizes_to_inner( + param_env, + lhs.to_alias_ty(ecx.tcx()).unwrap(), + rhs, + direction, + Invert::No, + )?; + ecx.normalizes_to_inner( + param_env, + rhs.to_alias_ty(ecx.tcx()).unwrap(), + lhs, + direction, + Invert::Yes, + )?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 9e8dbd0cde2..28138054ae5 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -49,7 +49,7 @@ pub(super) enum CandidateSource { /// Notable examples are auto traits, `Sized`, and `DiscriminantKind`. /// For a list of all traits with builtin impls, check out the /// [`EvalCtxt::assemble_builtin_impl_candidates`] method. Not - BuiltinImpl, + BuiltinImpl(BuiltinImplSource), /// An assumption from the environment. /// /// More precisely we've used the `n-th` assumption in the `param_env`. @@ -87,6 +87,16 @@ pub(super) enum CandidateSource { AliasBound, } +/// Records additional information about what kind of built-in impl this is. +/// This should only be used by selection. +#[derive(Debug, Clone, Copy)] +pub(super) enum BuiltinImplSource { + TraitUpcasting, + Object, + Misc, + Ambiguity, +} + /// Methods used to assemble candidates for either trait or projection goals. pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq + std::fmt::Display @@ -295,7 +305,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // least structurally resolve the type one layer. if goal.predicate.self_ty().is_ty_var() { return vec![Candidate { - source: CandidateSource::BuiltinImpl, + source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity), result: self .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) .unwrap(), @@ -321,11 +331,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { candidates } - /// If the self type of a goal is an alias, computing the relevant candidates is difficult. + /// If the self type of a goal is an alias we first try to normalize the self type + /// and compute the candidates for the normalized self type in case that succeeds. + /// + /// These candidates are used in addition to the ones with the alias as a self type. + /// We do this to simplify both builtin candidates and for better performance. + /// + /// We generate the builtin candidates on the fly by looking at the self type, e.g. + /// add `FnPtr` candidates if the self type is a function pointer. Handling builtin + /// candidates while the self type is still an alias seems difficult. This is similar + /// to `try_structurally_resolve_type` during hir typeck (FIXME once implemented). /// - /// To deal with this, we first try to normalize the self type and add the candidates for the normalized - /// self type to the list of candidates in case that succeeds. We also have to consider candidates with the - /// projection as a self type as well + /// Looking at all impls for some trait goal is prohibitively expensive. We therefore + /// only look at implementations with a matching self type. Because of this function, + /// we can avoid looking at all existing impls if the self type is an alias. #[instrument(level = "debug", skip_all)] fn assemble_candidates_after_normalizing_self_ty<G: GoalKind<'tcx>>( &mut self, @@ -344,7 +363,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let result = ecx.evaluate_added_goals_and_make_canonical_response( Certainty::Maybe(MaybeCause::Overflow), )?; - Ok(vec![Candidate { source: CandidateSource::BuiltinImpl, result }]) + Ok(vec![Candidate { + source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity), + result, + }]) }, |ecx| { let normalized_ty = ecx.next_ty_infer(); @@ -447,9 +469,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { }; match result { - Ok(result) => { - candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result }) - } + Ok(result) => candidates.push(Candidate { + source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), + result, + }), Err(NoSolution) => (), } @@ -457,7 +480,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // `trait Foo: Bar<A> + Bar<B>` and `dyn Foo: Unsize<dyn Bar<_>>` if lang_items.unsize_trait() == Some(trait_def_id) { for result in G::consider_builtin_dyn_upcast_candidates(self, goal) { - candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result }); + candidates.push(Candidate { + source: CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting), + result, + }); } } } @@ -621,9 +647,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { }; match result { - Ok(result) => { - candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result }) - } + Ok(result) => candidates.push(Candidate { + source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), + result, + }), Err(NoSolution) => (), } } @@ -688,9 +715,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } match G::consider_object_bound_candidate(self, goal, assumption) { - Ok(result) => { - candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result }) - } + Ok(result) => candidates.push(Candidate { + source: CandidateSource::BuiltinImpl(BuiltinImplSource::Object), + result, + }), Err(NoSolution) => (), } } @@ -711,8 +739,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { Err(_) => match self .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) { - Ok(result) => candidates - .push(Candidate { source: CandidateSource::BuiltinImpl, result }), + Ok(result) => candidates.push(Candidate { + source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity), + result, + }), // FIXME: This will be reachable at some point if we're in // `assemble_candidates_after_normalizing_self_ty` and we get a // universe error. We'll deal with it at this point. diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 9eac53c3983..3bb8cad15ab 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -28,7 +28,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( | ty::Char => Ok(vec![]), // Treat `str` like it's defined as `struct str([u8]);` - ty::Str => Ok(vec![tcx.mk_slice(tcx.types.u8)]), + ty::Str => Ok(vec![Ty::new_slice(tcx, tcx.types.u8)]), ty::Dynamic(..) | ty::Param(..) @@ -233,7 +233,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( { Ok(Some( sig.subst(tcx, substs) - .map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())), + .map_bound(|sig| (Ty::new_tup(tcx, sig.inputs()), sig.output())), )) } else { Err(NoSolution) @@ -242,7 +242,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed. ty::FnPtr(sig) => { if sig.is_fn_trait_compatible() { - Ok(Some(sig.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())))) + Ok(Some(sig.map_bound(|sig| (Ty::new_tup(tcx, sig.inputs()), sig.output())))) } else { Err(NoSolution) } diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs index 05248cb9d17..255620489ff 100644 --- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs +++ b/compiler/rustc_trait_selection/src/solve/canonicalize.rs @@ -283,7 +283,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> { // any equated inference vars correctly! let root_vid = self.infcx.root_var(vid); if root_vid != vid { - t = self.infcx.tcx.mk_ty_var(root_vid); + t = Ty::new_var(self.infcx.tcx, root_vid); vid = root_vid; } @@ -366,7 +366,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> { }), ); let bt = ty::BoundTy { var, kind: BoundTyKind::Anon }; - self.interner().mk_bound(self.binder_index, bt) + Ty::new_bound(self.infcx.tcx, self.binder_index, bt) } fn fold_const(&mut self, mut c: ty::Const<'tcx>) -> ty::Const<'tcx> { @@ -377,7 +377,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> { // any equated inference vars correctly! let root_vid = self.infcx.root_const_var(vid); if root_vid != vid { - c = self.infcx.tcx.mk_const(ty::InferConst::Var(root_vid), c.ty()); + c = ty::Const::new_var(self.infcx.tcx, root_vid, c.ty()); vid = root_vid; } @@ -426,6 +426,6 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> { var }), ); - self.interner().mk_const(ty::ConstKind::Bound(self.binder_index, var), c.ty()) + ty::Const::new_bound(self.infcx.tcx, self.binder_index, var, c.ty()) } } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 6aca40b8dbd..74dfbdddbab 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -9,7 +9,7 @@ use rustc_infer::infer::{ use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::ObligationCause; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_middle::traits::solve::inspect::{self, CandidateKind}; +use rustc_middle::traits::solve::inspect; use rustc_middle::traits::solve::{ CanonicalInput, CanonicalResponse, Certainty, IsNormalizesToHack, MaybeCause, PredefinedOpaques, PredefinedOpaquesData, QueryResult, @@ -19,7 +19,9 @@ use rustc_middle::ty::{ self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; +use rustc_session::config::DumpSolverProofTree; use rustc_span::DUMMY_SP; +use std::io::Write; use std::ops::ControlFlow; use crate::traits::specialization_graph; @@ -28,9 +30,11 @@ use super::inspect::ProofTreeBuilder; use super::search_graph::{self, OverflowHandler}; use super::SolverMode; use super::{search_graph::SearchGraph, Goal}; +pub use select::InferCtxtSelectExt; mod canonical; mod probe; +mod select; pub struct EvalCtxt<'a, 'tcx> { /// The inference context that backs (mostly) inference and placeholder terms @@ -111,9 +115,23 @@ impl NestedGoals<'_> { #[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)] pub enum GenerateProofTree { + Yes(UseGlobalCache), + No, +} + +#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)] +pub enum UseGlobalCache { Yes, No, } +impl UseGlobalCache { + pub fn from_bool(use_cache: bool) -> Self { + match use_cache { + true => UseGlobalCache::Yes, + false => UseGlobalCache::No, + } + } +} pub trait InferCtxtEvalExt<'tcx> { /// Evaluates a goal from **outside** of the trait solver. @@ -140,15 +158,34 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>, Option<inspect::GoalEvaluation<'tcx>>, ) { - let mode = if self.intercrate { SolverMode::Coherence } else { SolverMode::Normal }; - let mut search_graph = search_graph::SearchGraph::new(self.tcx, mode); + EvalCtxt::enter_root(self, generate_proof_tree, |ecx| { + ecx.evaluate_goal(IsNormalizesToHack::No, goal) + }) + } +} + +impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { + pub(super) fn solver_mode(&self) -> SolverMode { + self.search_graph.solver_mode() + } + + /// Creates a root evaluation context and search graph. This should only be + /// used from outside of any evaluation, and other methods should be preferred + /// over using this manually (such as [`InferCtxtEvalExt::evaluate_root_goal`]). + fn enter_root<R>( + infcx: &InferCtxt<'tcx>, + generate_proof_tree: GenerateProofTree, + f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> R, + ) -> (R, Option<inspect::GoalEvaluation<'tcx>>) { + let mode = if infcx.intercrate { SolverMode::Coherence } else { SolverMode::Normal }; + let mut search_graph = search_graph::SearchGraph::new(infcx.tcx, mode); let mut ecx = EvalCtxt { search_graph: &mut search_graph, - infcx: self, + infcx: infcx, // Only relevant when canonicalizing the response, // which we don't do within this evaluation context. - predefined_opaques_in_body: self + predefined_opaques_in_body: infcx .tcx .mk_predefined_opaques_in_body(PredefinedOpaquesData::default()), // Only relevant when canonicalizing the response. @@ -156,17 +193,17 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { var_values: CanonicalVarValues::dummy(), nested_goals: NestedGoals::new(), tainted: Ok(()), - inspect: (self.tcx.sess.opts.unstable_opts.dump_solver_proof_tree - || matches!(generate_proof_tree, GenerateProofTree::Yes)) - .then(ProofTreeBuilder::new_root) - .unwrap_or_else(ProofTreeBuilder::new_noop), + inspect: ProofTreeBuilder::new_maybe_root(infcx.tcx, generate_proof_tree), }; - let result = ecx.evaluate_goal(IsNormalizesToHack::No, goal); + let result = f(&mut ecx); let tree = ecx.inspect.finalize(); - if let Some(tree) = &tree { - // module to allow more granular RUSTC_LOG filtering to just proof tree output - super::inspect::dump::print_tree(tree); + if let (Some(tree), DumpSolverProofTree::Always) = + (&tree, infcx.tcx.sess.opts.unstable_opts.dump_solver_proof_tree) + { + let mut lock = std::io::stdout().lock(); + let _ = lock.write_fmt(format_args!("{tree:?}")); + let _ = lock.flush(); } assert!( @@ -177,11 +214,66 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { assert!(search_graph.is_empty()); (result, tree) } -} -impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { - pub(super) fn solver_mode(&self) -> SolverMode { - self.search_graph.solver_mode() + /// Creates a nested evaluation context that shares the same search graph as the + /// one passed in. This is suitable for evaluation, granted that the search graph + /// has had the nested goal recorded on its stack ([`SearchGraph::with_new_goal`]), + /// but it's preferable to use other methods that call this one rather than this + /// method directly. + /// + /// This function takes care of setting up the inference context, setting the anchor, + /// and registering opaques from the canonicalized input. + fn enter_canonical<R>( + tcx: TyCtxt<'tcx>, + search_graph: &'a mut search_graph::SearchGraph<'tcx>, + canonical_input: CanonicalInput<'tcx>, + goal_evaluation: &mut ProofTreeBuilder<'tcx>, + f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>, Goal<'tcx, ty::Predicate<'tcx>>) -> R, + ) -> R { + let intercrate = match search_graph.solver_mode() { + SolverMode::Normal => false, + SolverMode::Coherence => true, + }; + let (ref infcx, input, var_values) = tcx + .infer_ctxt() + .intercrate(intercrate) + .with_next_trait_solver(true) + .with_opaque_type_inference(canonical_input.value.anchor) + .build_with_canonical(DUMMY_SP, &canonical_input); + + let mut ecx = EvalCtxt { + infcx, + var_values, + predefined_opaques_in_body: input.predefined_opaques_in_body, + max_input_universe: canonical_input.max_universe, + search_graph, + nested_goals: NestedGoals::new(), + tainted: Ok(()), + inspect: goal_evaluation.new_goal_evaluation_step(input), + }; + + for &(key, ty) in &input.predefined_opaques_in_body.opaque_types { + ecx.insert_hidden_type(key, input.goal.param_env, ty) + .expect("failed to prepopulate opaque types"); + } + + if !ecx.nested_goals.is_empty() { + panic!("prepopulating opaque types shouldn't add goals: {:?}", ecx.nested_goals); + } + + let result = f(&mut ecx, input.goal); + + goal_evaluation.goal_evaluation_step(ecx.inspect); + + // When creating a query response we clone the opaque type constraints + // instead of taking them. This would cause an ICE here, since we have + // assertions against dropping an `InferCtxt` without taking opaques. + // FIXME: Once we remove support for the old impl we can remove this. + if input.anchor != DefiningAnchor::Error { + let _ = infcx.take_opaque_types(); + } + + result } /// The entry point of the solver. @@ -210,53 +302,17 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { canonical_input, goal_evaluation, |search_graph, goal_evaluation| { - let intercrate = match search_graph.solver_mode() { - SolverMode::Normal => false, - SolverMode::Coherence => true, - }; - let (ref infcx, input, var_values) = tcx - .infer_ctxt() - .intercrate(intercrate) - .with_next_trait_solver(true) - .with_opaque_type_inference(canonical_input.value.anchor) - .build_with_canonical(DUMMY_SP, &canonical_input); - - let mut ecx = EvalCtxt { - infcx, - var_values, - predefined_opaques_in_body: input.predefined_opaques_in_body, - max_input_universe: canonical_input.max_universe, + EvalCtxt::enter_canonical( + tcx, search_graph, - nested_goals: NestedGoals::new(), - tainted: Ok(()), - inspect: goal_evaluation.new_goal_evaluation_step(input), - }; - - for &(key, ty) in &input.predefined_opaques_in_body.opaque_types { - ecx.insert_hidden_type(key, input.goal.param_env, ty) - .expect("failed to prepopulate opaque types"); - } - - if !ecx.nested_goals.is_empty() { - panic!( - "prepopulating opaque types shouldn't add goals: {:?}", - ecx.nested_goals - ); - } - - let result = ecx.compute_goal(input.goal); - ecx.inspect.query_result(result); - goal_evaluation.goal_evaluation_step(ecx.inspect); - - // When creating a query response we clone the opaque type constraints - // instead of taking them. This would cause an ICE here, since we have - // assertions against dropping an `InferCtxt` without taking opaques. - // FIXME: Once we remove support for the old impl we can remove this. - if input.anchor != DefiningAnchor::Error { - let _ = infcx.take_opaque_types(); - } - - result + canonical_input, + goal_evaluation, + |ecx, goal| { + let result = ecx.compute_goal(goal); + ecx.inspect.query_result(result); + result + }, + ) }, ) } @@ -385,24 +441,20 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { self.compute_well_formed_goal(Goal { param_env, predicate: arg }) } - ty::PredicateKind::Ambiguous => { - self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - } - // FIXME: implement this predicate :) - ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(_)) => { - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => { + self.compute_const_evaluatable_goal(Goal { param_env, predicate: ct }) } ty::PredicateKind::ConstEquate(_, _) => { bug!("ConstEquate should not be emitted when `-Ztrait-solver=next` is active") } - ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => { - bug!("TypeWellFormedFromEnv is only used for Chalk") - } ty::PredicateKind::AliasRelate(lhs, rhs, direction) => self .compute_alias_relate_goal(Goal { param_env, predicate: (lhs, rhs, direction), }), + ty::PredicateKind::Ambiguous => { + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + } } } else { let kind = self.infcx.instantiate_binder_with_placeholders(kind); @@ -785,7 +837,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } - pub(super) fn can_define_opaque_ty(&mut self, def_id: LocalDefId) -> bool { + pub(super) fn can_define_opaque_ty(&self, def_id: LocalDefId) -> bool { self.infcx.opaque_type_origin(def_id).is_some() } @@ -843,25 +895,19 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { if candidate_key.def_id != key.def_id { continue; } - values.extend( - self.probe(|r| CandidateKind::Candidate { - name: "opaque type storage".into(), - result: *r, - }) - .enter(|ecx| { - for (a, b) in std::iter::zip(candidate_key.substs, key.substs) { - ecx.eq(param_env, a, b)?; - } - ecx.eq(param_env, candidate_ty, ty)?; - ecx.add_item_bounds_for_hidden_type( - candidate_key.def_id.to_def_id(), - candidate_key.substs, - param_env, - candidate_ty, - ); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }), - ); + values.extend(self.probe_candidate("opaque type storage").enter(|ecx| { + for (a, b) in std::iter::zip(candidate_key.substs, key.substs) { + ecx.eq(param_env, a, b)?; + } + ecx.eq(param_env, candidate_ty, ty)?; + ecx.add_item_bounds_for_hidden_type( + candidate_key.def_id.to_def_id(), + candidate_key.substs, + param_env, + candidate_ty, + ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + })); } values } @@ -878,7 +924,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { use rustc_middle::mir::interpret::ErrorHandled; match self.infcx.try_const_eval_resolve(param_env, unevaluated, ty, None) { Ok(ct) => Some(ct), - Err(ErrorHandled::Reported(e)) => Some(self.tcx().const_error(ty, e.into())), + Err(ErrorHandled::Reported(e)) => Some(ty::Const::new_error(self.tcx(), e.into(), ty)), Err(ErrorHandled::TooGeneric) => None, } } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index 851edf1fa1c..637d458882c 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -20,7 +20,7 @@ use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{ ExternalConstraints, ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput, }; -use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty}; +use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable}; use rustc_span::DUMMY_SP; use std::iter; use std::ops::Deref; @@ -28,10 +28,10 @@ use std::ops::Deref; impl<'tcx> EvalCtxt<'_, 'tcx> { /// Canonicalizes the goal remembering the original values /// for each bound variable. - pub(super) fn canonicalize_goal( + pub(super) fn canonicalize_goal<T: TypeFoldable<TyCtxt<'tcx>>>( &self, - goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> (Vec<ty::GenericArg<'tcx>>, CanonicalInput<'tcx>) { + goal: Goal<'tcx, T>, + ) -> (Vec<ty::GenericArg<'tcx>>, CanonicalInput<'tcx, T>) { let mut orig_values = Default::default(); let canonical_goal = Canonicalizer::canonicalize( self.infcx, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs index 5d912fc039d..4477ea7d501 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs @@ -1,5 +1,5 @@ use super::EvalCtxt; -use rustc_middle::traits::solve::inspect; +use rustc_middle::traits::solve::{inspect, QueryResult}; use std::marker::PhantomData; pub(in crate::solve) struct ProbeCtxt<'me, 'a, 'tcx, F, T> { @@ -44,4 +44,24 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { { ProbeCtxt { ecx: self, probe_kind, _result: PhantomData } } + + pub(in crate::solve) fn probe_candidate( + &mut self, + name: &'static str, + ) -> ProbeCtxt< + '_, + 'a, + 'tcx, + impl FnOnce(&QueryResult<'tcx>) -> inspect::CandidateKind<'tcx>, + QueryResult<'tcx>, + > { + ProbeCtxt { + ecx: self, + probe_kind: move |result: &QueryResult<'tcx>| inspect::CandidateKind::Candidate { + name: name.to_string(), + result: *result, + }, + _result: PhantomData, + } + } } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs new file mode 100644 index 00000000000..0800738a3f2 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs @@ -0,0 +1,307 @@ +use std::ops::ControlFlow; + +use rustc_hir::def_id::DefId; +use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; +use rustc_infer::traits::util::supertraits; +use rustc_infer::traits::{ + Obligation, PredicateObligation, Selection, SelectionResult, TraitObligation, +}; +use rustc_middle::traits::solve::{CanonicalInput, Certainty, Goal}; +use rustc_middle::traits::{ + ImplSource, ImplSourceObjectData, ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, + ObligationCause, SelectionError, +}; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::DUMMY_SP; + +use crate::solve::assembly::{BuiltinImplSource, Candidate, CandidateSource}; +use crate::solve::eval_ctxt::{EvalCtxt, GenerateProofTree}; +use crate::solve::inspect::ProofTreeBuilder; +use crate::solve::search_graph::OverflowHandler; +use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment}; + +pub trait InferCtxtSelectExt<'tcx> { + fn select_in_new_trait_solver( + &self, + obligation: &TraitObligation<'tcx>, + ) -> SelectionResult<'tcx, Selection<'tcx>>; +} + +impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> { + fn select_in_new_trait_solver( + &self, + obligation: &TraitObligation<'tcx>, + ) -> SelectionResult<'tcx, Selection<'tcx>> { + assert!(self.next_trait_solver()); + + let trait_goal = Goal::new( + self.tcx, + obligation.param_env, + self.instantiate_binder_with_placeholders(obligation.predicate), + ); + + let (result, _) = EvalCtxt::enter_root(self, GenerateProofTree::No, |ecx| { + let goal = Goal::new(ecx.tcx(), trait_goal.param_env, trait_goal.predicate); + let (orig_values, canonical_goal) = ecx.canonicalize_goal(goal); + let mut candidates = ecx.compute_canonical_trait_candidates(canonical_goal); + + // pseudo-winnow + if candidates.len() == 0 { + return Err(SelectionError::Unimplemented); + } else if candidates.len() > 1 { + let mut i = 0; + while i < candidates.len() { + let should_drop_i = (0..candidates.len()).filter(|&j| i != j).any(|j| { + candidate_should_be_dropped_in_favor_of( + ecx.tcx(), + &candidates[i], + &candidates[j], + ) + }); + if should_drop_i { + candidates.swap_remove(i); + } else { + i += 1; + if i > 1 { + return Ok(None); + } + } + } + } + + let candidate = candidates.pop().unwrap(); + let (certainty, nested_goals) = ecx + .instantiate_and_apply_query_response( + trait_goal.param_env, + orig_values, + candidate.result, + ) + .map_err(|_| SelectionError::Unimplemented)?; + + Ok(Some((candidate, certainty, nested_goals))) + }); + + let (candidate, certainty, nested_goals) = match result { + Ok(Some((candidate, certainty, nested_goals))) => (candidate, certainty, nested_goals), + Ok(None) => return Ok(None), + Err(e) => return Err(e), + }; + + let nested_obligations: Vec<_> = nested_goals + .into_iter() + .map(|goal| { + Obligation::new(self.tcx, ObligationCause::dummy(), goal.param_env, goal.predicate) + }) + .collect(); + + let goal = self.resolve_vars_if_possible(trait_goal); + match (certainty, candidate.source) { + // Rematching the implementation will instantiate the same nested goals that + // would have caused the ambiguity, so we can still make progress here regardless. + (_, CandidateSource::Impl(def_id)) => { + rematch_impl(self, goal, def_id, nested_obligations) + } + + // Rematching the dyn upcast or object goal will instantiate the same nested + // goals that would have caused the ambiguity, so we can still make progress here + // regardless. + // FIXME: This doesn't actually check the object bounds hold here. + ( + _, + CandidateSource::BuiltinImpl( + BuiltinImplSource::Object | BuiltinImplSource::TraitUpcasting, + ), + ) => rematch_object(self, goal, nested_obligations), + + // Technically some builtin impls have nested obligations, but if + // `Certainty::Yes`, then they should've all been verified and don't + // need re-checking. + (Certainty::Yes, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc)) => { + Ok(Some(ImplSource::Builtin(nested_obligations))) + } + + // It's fine not to do anything to rematch these, since there are no + // nested obligations. + (Certainty::Yes, CandidateSource::ParamEnv(_) | CandidateSource::AliasBound) => { + Ok(Some(ImplSource::Param(nested_obligations, ty::BoundConstness::NotConst))) + } + + (_, CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity)) + | (Certainty::Maybe(_), _) => Ok(None), + } + } +} + +impl<'tcx> EvalCtxt<'_, 'tcx> { + fn compute_canonical_trait_candidates( + &mut self, + canonical_input: CanonicalInput<'tcx>, + ) -> Vec<Candidate<'tcx>> { + // This doesn't record the canonical goal on the stack during the + // candidate assembly step, but that's fine. Selection is conceptually + // outside of the solver, and if there were any cycles, we'd encounter + // the cycle anyways one step later. + EvalCtxt::enter_canonical( + self.tcx(), + self.search_graph(), + canonical_input, + // FIXME: This is wrong, idk if we even want to track stuff here. + &mut ProofTreeBuilder::new_noop(), + |ecx, goal| { + let trait_goal = Goal { + param_env: goal.param_env, + predicate: goal + .predicate + .to_opt_poly_trait_pred() + .expect("we canonicalized a trait goal") + .no_bound_vars() + .expect("we instantiated all bound vars"), + }; + ecx.assemble_and_evaluate_candidates(trait_goal) + }, + ) + } +} + +fn candidate_should_be_dropped_in_favor_of<'tcx>( + tcx: TyCtxt<'tcx>, + victim: &Candidate<'tcx>, + other: &Candidate<'tcx>, +) -> bool { + match (victim.source, other.source) { + (CandidateSource::ParamEnv(victim_idx), CandidateSource::ParamEnv(other_idx)) => { + victim_idx >= other_idx + } + (_, CandidateSource::ParamEnv(_)) => true, + + ( + CandidateSource::BuiltinImpl(BuiltinImplSource::Object), + CandidateSource::BuiltinImpl(BuiltinImplSource::Object), + ) => false, + (_, CandidateSource::BuiltinImpl(BuiltinImplSource::Object)) => true, + + (CandidateSource::Impl(victim_def_id), CandidateSource::Impl(other_def_id)) => { + tcx.specializes((other_def_id, victim_def_id)) + && other.result.value.certainty == Certainty::Yes + } + + _ => false, + } +} + +fn rematch_impl<'tcx>( + infcx: &InferCtxt<'tcx>, + goal: Goal<'tcx, ty::TraitPredicate<'tcx>>, + impl_def_id: DefId, + mut nested: Vec<PredicateObligation<'tcx>>, +) -> SelectionResult<'tcx, Selection<'tcx>> { + let substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); + let impl_trait_ref = infcx.tcx.impl_trait_ref(impl_def_id).unwrap().subst(infcx.tcx, substs); + + nested.extend( + infcx + .at(&ObligationCause::dummy(), goal.param_env) + .eq(DefineOpaqueTypes::No, goal.predicate.trait_ref, impl_trait_ref) + .map_err(|_| SelectionError::Unimplemented)? + .into_obligations(), + ); + + nested.extend( + infcx.tcx.predicates_of(impl_def_id).instantiate(infcx.tcx, substs).into_iter().map( + |(pred, _)| Obligation::new(infcx.tcx, ObligationCause::dummy(), goal.param_env, pred), + ), + ); + + Ok(Some(ImplSource::UserDefined(ImplSourceUserDefinedData { impl_def_id, substs, nested }))) +} + +fn rematch_object<'tcx>( + infcx: &InferCtxt<'tcx>, + goal: Goal<'tcx, ty::TraitPredicate<'tcx>>, + mut nested: Vec<PredicateObligation<'tcx>>, +) -> SelectionResult<'tcx, Selection<'tcx>> { + let self_ty = goal.predicate.self_ty(); + let ty::Dynamic(data, _, source_kind) = *self_ty.kind() + else { + bug!() + }; + let source_trait_ref = data.principal().unwrap().with_self_ty(infcx.tcx, self_ty); + + let (is_upcasting, target_trait_ref_unnormalized) = if Some(goal.predicate.def_id()) + == infcx.tcx.lang_items().unsize_trait() + { + assert_eq!(source_kind, ty::Dyn, "cannot upcast dyn*"); + if let ty::Dynamic(data, _, ty::Dyn) = goal.predicate.trait_ref.substs.type_at(1).kind() { + (true, data.principal().unwrap().with_self_ty(infcx.tcx, self_ty)) + } else { + bug!() + } + } else { + (false, ty::Binder::dummy(goal.predicate.trait_ref)) + }; + + let mut target_trait_ref = None; + for candidate_trait_ref in supertraits(infcx.tcx, source_trait_ref) { + let result = infcx.commit_if_ok(|_| { + infcx.at(&ObligationCause::dummy(), goal.param_env).eq( + DefineOpaqueTypes::No, + target_trait_ref_unnormalized, + candidate_trait_ref, + ) + + // FIXME: We probably should at least shallowly verify these... + }); + + match result { + Ok(InferOk { value: (), obligations }) => { + target_trait_ref = Some(candidate_trait_ref); + nested.extend(obligations); + break; + } + Err(_) => continue, + } + } + + let target_trait_ref = target_trait_ref.unwrap(); + + let mut offset = 0; + let Some((vtable_base, vtable_vptr_slot)) = + prepare_vtable_segments(infcx.tcx, source_trait_ref, |segment| { + match segment { + VtblSegment::MetadataDSA => { + offset += TyCtxt::COMMON_VTABLE_ENTRIES.len(); + } + VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { + let own_vtable_entries = count_own_vtable_entries(infcx.tcx, trait_ref); + + if trait_ref == target_trait_ref { + if emit_vptr { + return ControlFlow::Break(( + offset, + Some(offset + count_own_vtable_entries(infcx.tcx, trait_ref)), + )); + } else { + return ControlFlow::Break((offset, None)); + } + } + + offset += own_vtable_entries; + if emit_vptr { + offset += 1; + } + } + } + ControlFlow::Continue(()) + }) + else { + bug!(); + }; + + // If we're upcasting, get the offset of the vtable pointer, otherwise get + // the base of the vtable. + Ok(Some(if is_upcasting { + ImplSource::TraitUpcasting(ImplSourceTraitUpcastingData { vtable_vptr_slot, nested }) + } else { + ImplSource::Object(ImplSourceObjectData { vtable_base, nested }) + })) +} diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index fc848fe3080..88ee14c4db5 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -41,6 +41,7 @@ impl<'tcx> FulfillmentCtxt<'tcx> { } impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { + #[instrument(level = "debug", skip(self, infcx))] fn register_predicate_obligation( &mut self, infcx: &InferCtxt<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/inspect.rs b/compiler/rustc_trait_selection/src/solve/inspect.rs index 6d7804a8fad..2d6717fdad9 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect.rs @@ -3,9 +3,11 @@ use rustc_middle::traits::solve::inspect::{self, CacheHit, CandidateKind}; use rustc_middle::traits::solve::{ CanonicalInput, Certainty, Goal, IsNormalizesToHack, QueryInput, QueryResult, }; -use rustc_middle::ty; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_session::config::DumpSolverProofTree; -pub mod dump; +use super::eval_ctxt::UseGlobalCache; +use super::GenerateProofTree; #[derive(Eq, PartialEq, Debug, Hash, HashStable)] pub struct WipGoalEvaluation<'tcx> { @@ -144,20 +146,42 @@ impl<'tcx> From<WipGoalCandidate<'tcx>> for DebugSolver<'tcx> { } pub struct ProofTreeBuilder<'tcx> { - state: Option<Box<DebugSolver<'tcx>>>, + state: Option<Box<BuilderData<'tcx>>>, +} + +struct BuilderData<'tcx> { + tree: DebugSolver<'tcx>, + use_global_cache: UseGlobalCache, } impl<'tcx> ProofTreeBuilder<'tcx> { - fn new(state: impl Into<DebugSolver<'tcx>>) -> ProofTreeBuilder<'tcx> { - ProofTreeBuilder { state: Some(Box::new(state.into())) } + fn new( + state: impl Into<DebugSolver<'tcx>>, + use_global_cache: UseGlobalCache, + ) -> ProofTreeBuilder<'tcx> { + ProofTreeBuilder { + state: Some(Box::new(BuilderData { tree: state.into(), use_global_cache })), + } + } + + fn nested(&self, state: impl Into<DebugSolver<'tcx>>) -> Self { + match &self.state { + Some(prev_state) => Self { + state: Some(Box::new(BuilderData { + tree: state.into(), + use_global_cache: prev_state.use_global_cache, + })), + }, + None => Self { state: None }, + } } fn as_mut(&mut self) -> Option<&mut DebugSolver<'tcx>> { - self.state.as_mut().map(|boxed| &mut **boxed) + self.state.as_mut().map(|boxed| &mut boxed.tree) } pub fn finalize(self) -> Option<inspect::GoalEvaluation<'tcx>> { - match *(self.state?) { + match self.state?.tree { DebugSolver::GoalEvaluation(wip_goal_evaluation) => { Some(wip_goal_evaluation.finalize()) } @@ -165,8 +189,46 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } - pub fn new_root() -> ProofTreeBuilder<'tcx> { - ProofTreeBuilder::new(DebugSolver::Root) + pub fn use_global_cache(&self) -> bool { + self.state + .as_ref() + .map(|state| matches!(state.use_global_cache, UseGlobalCache::Yes)) + .unwrap_or(true) + } + + pub fn new_maybe_root( + tcx: TyCtxt<'tcx>, + generate_proof_tree: GenerateProofTree, + ) -> ProofTreeBuilder<'tcx> { + let generate_proof_tree = match ( + tcx.sess.opts.unstable_opts.dump_solver_proof_tree, + tcx.sess.opts.unstable_opts.dump_solver_proof_tree_use_cache, + generate_proof_tree, + ) { + (_, Some(use_cache), GenerateProofTree::Yes(_)) => { + GenerateProofTree::Yes(UseGlobalCache::from_bool(use_cache)) + } + + (DumpSolverProofTree::Always, use_cache, GenerateProofTree::No) => { + let use_cache = use_cache.unwrap_or(true); + GenerateProofTree::Yes(UseGlobalCache::from_bool(use_cache)) + } + + (_, None, GenerateProofTree::Yes(_)) => generate_proof_tree, + (DumpSolverProofTree::Never, _, _) => generate_proof_tree, + (DumpSolverProofTree::OnError, _, _) => generate_proof_tree, + }; + + match generate_proof_tree { + GenerateProofTree::No => ProofTreeBuilder::new_noop(), + GenerateProofTree::Yes(global_cache_disabled) => { + ProofTreeBuilder::new_root(global_cache_disabled) + } + } + } + + pub fn new_root(use_global_cache: UseGlobalCache) -> ProofTreeBuilder<'tcx> { + ProofTreeBuilder::new(DebugSolver::Root, use_global_cache) } pub fn new_noop() -> ProofTreeBuilder<'tcx> { @@ -186,7 +248,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { return ProofTreeBuilder { state: None }; } - ProofTreeBuilder::new(WipGoalEvaluation { + self.nested(WipGoalEvaluation { uncanonicalized_goal: goal, canonicalized_goal: None, evaluation_steps: vec![], @@ -232,7 +294,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<'tcx>) { if let Some(this) = self.as_mut() { - match (this, *goal_evaluation.state.unwrap()) { + match (this, goal_evaluation.state.unwrap().tree) { ( DebugSolver::AddedGoalsEvaluation(WipAddedGoalsEvaluation { evaluations, .. @@ -253,7 +315,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { return ProofTreeBuilder { state: None }; } - ProofTreeBuilder::new(WipGoalEvaluationStep { + self.nested(WipGoalEvaluationStep { instantiated_goal, nested_goal_evaluations: vec![], candidates: vec![], @@ -262,7 +324,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } pub fn goal_evaluation_step(&mut self, goal_eval_step: ProofTreeBuilder<'tcx>) { if let Some(this) = self.as_mut() { - match (this, *goal_eval_step.state.unwrap()) { + match (this, goal_eval_step.state.unwrap().tree) { (DebugSolver::GoalEvaluation(goal_eval), DebugSolver::GoalEvaluationStep(step)) => { goal_eval.evaluation_steps.push(step); } @@ -276,7 +338,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { return ProofTreeBuilder { state: None }; } - ProofTreeBuilder::new(WipGoalCandidate { + self.nested(WipGoalCandidate { nested_goal_evaluations: vec![], candidates: vec![], kind: None, @@ -296,7 +358,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { pub fn goal_candidate(&mut self, candidate: ProofTreeBuilder<'tcx>) { if let Some(this) = self.as_mut() { - match (this, *candidate.state.unwrap()) { + match (this, candidate.state.unwrap().tree) { ( DebugSolver::GoalCandidate(WipGoalCandidate { candidates, .. }) | DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { candidates, .. }), @@ -312,7 +374,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { return ProofTreeBuilder { state: None }; } - ProofTreeBuilder::new(WipAddedGoalsEvaluation { evaluations: vec![], result: None }) + self.nested(WipAddedGoalsEvaluation { evaluations: vec![], result: None }) } pub fn evaluate_added_goals_loop_start(&mut self) { @@ -339,7 +401,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { pub fn added_goals_evaluation(&mut self, goals_evaluation: ProofTreeBuilder<'tcx>) { if let Some(this) = self.as_mut() { - match (this, *goals_evaluation.state.unwrap()) { + match (this, goals_evaluation.state.unwrap().tree) { ( DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { nested_goal_evaluations, diff --git a/compiler/rustc_trait_selection/src/solve/inspect/dump.rs b/compiler/rustc_trait_selection/src/solve/inspect/dump.rs deleted file mode 100644 index b755ee86215..00000000000 --- a/compiler/rustc_trait_selection/src/solve/inspect/dump.rs +++ /dev/null @@ -1,5 +0,0 @@ -use rustc_middle::traits::solve::inspect::GoalEvaluation; - -pub fn print_tree(tree: &GoalEvaluation<'_>) { - debug!(?tree); -} diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 49fecedc0ca..77809d8d2ba 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -26,14 +26,18 @@ mod canonicalize; mod eval_ctxt; mod fulfill; pub mod inspect; +mod normalize; mod opaques; mod project_goals; mod search_graph; mod trait_goals; mod weak_types; -pub use eval_ctxt::{EvalCtxt, InferCtxtEvalExt}; +pub use eval_ctxt::{ + EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt, UseGlobalCache, +}; pub use fulfill::FulfillmentCtxt; +pub(crate) use normalize::deeply_normalize; #[derive(Debug, Clone, Copy)] enum SolverMode { @@ -157,6 +161,43 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] + fn compute_const_evaluatable_goal( + &mut self, + Goal { param_env, predicate: ct }: Goal<'tcx, ty::Const<'tcx>>, + ) -> QueryResult<'tcx> { + match ct.kind() { + ty::ConstKind::Unevaluated(uv) => { + // We never return `NoSolution` here as `try_const_eval_resolve` emits an + // error itself when failing to evaluate, so emitting an additional fulfillment + // error in that case is unnecessary noise. This may change in the future once + // evaluation failures are allowed to impact selection, e.g. generic const + // expressions in impl headers or `where`-clauses. + + // FIXME(generic_const_exprs): Implement handling for generic + // const expressions here. + if let Some(_normalized) = self.try_const_eval_resolve(param_env, uv, ct.ty()) { + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } else { + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + } + } + ty::ConstKind::Infer(_) => { + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + } + ty::ConstKind::Placeholder(_) | ty::ConstKind::Value(_) | ty::ConstKind::Error(_) => { + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + // We can freely ICE here as: + // - `Param` gets replaced with a placeholder during canonicalization + // - `Bound` cannot exist as we don't have a binder around the self Type + // - `Expr` is part of `feature(generic_const_exprs)` and is not implemented yet + ty::ConstKind::Param(_) | ty::ConstKind::Bound(_, _) | ty::ConstKind::Expr(_) => { + bug!("unexpect const kind: {:?}", ct) + } + } + } + #[instrument(level = "debug", skip(self), ret)] fn compute_const_arg_has_type_goal( &mut self, diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs new file mode 100644 index 00000000000..c0ee1a576e5 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -0,0 +1,222 @@ +use crate::traits::error_reporting::TypeErrCtxtExt; +use crate::traits::query::evaluate_obligation::InferCtxtExt; +use crate::traits::{needs_normalization, BoundVarReplacer, PlaceholderReplacer}; +use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_infer::infer::at::At; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::traits::TraitEngineExt; +use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine}; +use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; +use rustc_middle::traits::Reveal; +use rustc_middle::ty::{self, AliasTy, Ty, TyCtxt, UniverseIndex}; +use rustc_middle::ty::{FallibleTypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::{TypeFoldable, TypeVisitableExt}; + +use super::FulfillmentCtxt; + +/// Deeply normalize all aliases in `value`. This does not handle inference and expects +/// its input to be already fully resolved. +pub(crate) fn deeply_normalize<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( + at: At<'_, 'tcx>, + value: T, +) -> Result<T, Vec<FulfillmentError<'tcx>>> { + let fulfill_cx = FulfillmentCtxt::new(at.infcx); + let mut folder = NormalizationFolder { at, fulfill_cx, depth: 0, universes: Vec::new() }; + + value.try_fold_with(&mut folder) +} + +struct NormalizationFolder<'me, 'tcx> { + at: At<'me, 'tcx>, + fulfill_cx: FulfillmentCtxt<'tcx>, + depth: usize, + universes: Vec<Option<UniverseIndex>>, +} + +impl<'tcx> NormalizationFolder<'_, 'tcx> { + fn normalize_alias_ty( + &mut self, + alias: AliasTy<'tcx>, + ) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>> { + let infcx = self.at.infcx; + let tcx = infcx.tcx; + let recursion_limit = tcx.recursion_limit(); + if !recursion_limit.value_within_limit(self.depth) { + self.at.infcx.err_ctxt().report_overflow_error( + &alias.to_ty(tcx), + self.at.cause.span, + true, + |_| {}, + ); + } + + self.depth += 1; + + let new_infer_ty = infcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::NormalizeProjectionType, + span: self.at.cause.span, + }); + let obligation = Obligation::new( + tcx, + self.at.cause.clone(), + self.at.param_env, + ty::Binder::dummy(ty::ProjectionPredicate { + projection_ty: alias, + term: new_infer_ty.into(), + }), + ); + + // Do not emit an error if normalization is known to fail but instead + // keep the projection unnormalized. This is the case for projections + // with a `T: Trait` where-clause and opaque types outside of the defining + // scope. + let result = if infcx.predicate_may_hold(&obligation) { + self.fulfill_cx.register_predicate_obligation(infcx, obligation); + let errors = self.fulfill_cx.select_all_or_error(infcx); + if !errors.is_empty() { + return Err(errors); + } + let ty = infcx.resolve_vars_if_possible(new_infer_ty); + ty.try_fold_with(self)? + } else { + alias.to_ty(tcx).try_super_fold_with(self)? + }; + + self.depth -= 1; + Ok(result) + } + + fn normalize_unevaluated_const( + &mut self, + ty: Ty<'tcx>, + uv: ty::UnevaluatedConst<'tcx>, + ) -> Result<ty::Const<'tcx>, Vec<FulfillmentError<'tcx>>> { + let infcx = self.at.infcx; + let tcx = infcx.tcx; + let recursion_limit = tcx.recursion_limit(); + if !recursion_limit.value_within_limit(self.depth) { + self.at.infcx.err_ctxt().report_overflow_error( + &ty::Const::new_unevaluated(tcx, uv, ty), + self.at.cause.span, + true, + |_| {}, + ); + } + + self.depth += 1; + + let new_infer_ct = infcx.next_const_var( + ty, + ConstVariableOrigin { + kind: ConstVariableOriginKind::MiscVariable, + span: self.at.cause.span, + }, + ); + let obligation = Obligation::new( + tcx, + self.at.cause.clone(), + self.at.param_env, + ty::Binder::dummy(ty::ProjectionPredicate { + projection_ty: tcx.mk_alias_ty(uv.def, uv.substs), + term: new_infer_ct.into(), + }), + ); + + let result = if infcx.predicate_may_hold(&obligation) { + self.fulfill_cx.register_predicate_obligation(infcx, obligation); + let errors = self.fulfill_cx.select_all_or_error(infcx); + if !errors.is_empty() { + return Err(errors); + } + let ct = infcx.resolve_vars_if_possible(new_infer_ct); + ct.try_fold_with(self)? + } else { + ty::Const::new_unevaluated(tcx, uv, ty).try_super_fold_with(self)? + }; + + self.depth -= 1; + Ok(result) + } +} + +impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> { + type Error = Vec<FulfillmentError<'tcx>>; + + fn interner(&self) -> TyCtxt<'tcx> { + self.at.infcx.tcx + } + + fn try_fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>( + &mut self, + t: ty::Binder<'tcx, T>, + ) -> Result<ty::Binder<'tcx, T>, Self::Error> { + self.universes.push(None); + let t = t.try_super_fold_with(self)?; + self.universes.pop(); + Ok(t) + } + + fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> { + let reveal = self.at.param_env.reveal(); + let infcx = self.at.infcx; + debug_assert_eq!(ty, infcx.shallow_resolve(ty)); + if !needs_normalization(&ty, reveal) { + return Ok(ty); + } + + // We don't normalize opaque types unless we have + // `Reveal::All`, even if we're in the defining scope. + let data = match *ty.kind() { + ty::Alias(kind, alias_ty) if kind != ty::Opaque || reveal == Reveal::UserFacing => { + alias_ty + } + _ => return ty.try_super_fold_with(self), + }; + + if data.has_escaping_bound_vars() { + let (data, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); + let result = ensure_sufficient_stack(|| self.normalize_alias_ty(data))?; + Ok(PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + &mut self.universes, + result, + )) + } else { + ensure_sufficient_stack(|| self.normalize_alias_ty(data)) + } + } + + fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> { + let reveal = self.at.param_env.reveal(); + let infcx = self.at.infcx; + debug_assert_eq!(ct, infcx.shallow_resolve(ct)); + if !needs_normalization(&ct, reveal) { + return Ok(ct); + } + + let uv = match ct.kind() { + ty::ConstKind::Unevaluated(ct) => ct, + _ => return ct.try_super_fold_with(self), + }; + + if uv.has_escaping_bound_vars() { + let (uv, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, uv); + let result = ensure_sufficient_stack(|| self.normalize_unevaluated_const(ct.ty(), uv))?; + Ok(PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + &mut self.universes, + result, + )) + } else { + ensure_sufficient_stack(|| self.normalize_unevaluated_const(ct.ty(), uv)) + } + } +} diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index cbea8009f02..aa690719970 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -112,23 +112,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ) -> QueryResult<'tcx> { if let Some(projection_pred) = assumption.as_projection_clause() { if projection_pred.projection_def_id() == goal.predicate.def_id() { - ecx.probe(|r| CandidateKind::Candidate { name: "assumption".into(), result: *r }) - .enter(|ecx| { - let assumption_projection_pred = - ecx.instantiate_binder_with_infer(projection_pred); - ecx.eq( - goal.param_env, - goal.predicate.projection_ty, - assumption_projection_pred.projection_ty, - )?; - ecx.eq( - goal.param_env, - goal.predicate.term, - assumption_projection_pred.term, - ) + ecx.probe_candidate("assumption").enter(|ecx| { + let assumption_projection_pred = + ecx.instantiate_binder_with_infer(projection_pred); + ecx.eq( + goal.param_env, + goal.predicate.projection_ty, + assumption_projection_pred.projection_ty, + )?; + ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term) .expect("expected goal term to be fully unconstrained"); - then(ecx) - }) + then(ecx) + }) } else { Err(NoSolution) } @@ -186,14 +181,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { "missing value for assoc item in impl", ); let error_term = match assoc_def.item.kind { - ty::AssocKind::Const => tcx - .const_error( - tcx.type_of(goal.predicate.def_id()) - .subst(tcx, goal.predicate.projection_ty.substs), - guar, + ty::AssocKind::Const => ty::Const::new_error(tcx, + guar, + tcx.type_of(goal.predicate.def_id()) + .subst(tcx, goal.predicate.projection_ty.substs), ) .into(), - ty::AssocKind::Type => tcx.ty_error(guar).into(), + ty::AssocKind::Type => Ty::new_error(tcx,guar).into(), ty::AssocKind::Fn => unreachable!(), }; ecx.eq(goal.param_env, goal.predicate.term, error_term) @@ -329,69 +323,53 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { let tcx = ecx.tcx(); - ecx.probe(|r| CandidateKind::Candidate { name: "builtin pointee".into(), result: *r }) - .enter(|ecx| { - let metadata_ty = match goal.predicate.self_ty().kind() { - ty::Bool - | ty::Char - | ty::Int(..) - | ty::Uint(..) - | ty::Float(..) - | ty::Array(..) - | ty::RawPtr(..) - | ty::Ref(..) - | ty::FnDef(..) - | ty::FnPtr(..) - | ty::Closure(..) - | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) - | ty::Generator(..) - | ty::GeneratorWitness(..) - | ty::GeneratorWitnessMIR(..) - | ty::Never - | ty::Foreign(..) => tcx.types.unit, - - ty::Error(e) => tcx.ty_error(*e), - - ty::Str | ty::Slice(_) => tcx.types.usize, - - ty::Dynamic(_, _, _) => { - let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None); - tcx.type_of(dyn_metadata) - .subst(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())]) - } - - ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => { - // FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints. - let sized_predicate = ty::TraitRef::from_lang_item( - tcx, - LangItem::Sized, - DUMMY_SP, - [ty::GenericArg::from(goal.predicate.self_ty())], - ); - ecx.add_goal(goal.with(tcx, sized_predicate)); - tcx.types.unit - } + ecx.probe_candidate("builtin pointee").enter(|ecx| { + let metadata_ty = match goal.predicate.self_ty().kind() { + ty::Bool + | ty::Char + | ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::Array(..) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Closure(..) + | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) + | ty::Never + | ty::Foreign(..) => tcx.types.unit, + + ty::Error(e) => Ty::new_error(tcx, *e), + + ty::Str | ty::Slice(_) => tcx.types.usize, + + ty::Dynamic(_, _, _) => { + let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None); + tcx.type_of(dyn_metadata) + .subst(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())]) + } - ty::Adt(def, substs) if def.is_struct() => { - match def.non_enum_variant().fields.raw.last() { - None => tcx.types.unit, - Some(field_def) => { - let self_ty = field_def.ty(tcx, substs); - ecx.add_goal(goal.with( - tcx, - ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)), - )); - return ecx.evaluate_added_goals_and_make_canonical_response( - Certainty::Yes, - ); - } - } - } - ty::Adt(_, _) => tcx.types.unit, + ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => { + // FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints. + let sized_predicate = ty::TraitRef::from_lang_item( + tcx, + LangItem::Sized, + DUMMY_SP, + [ty::GenericArg::from(goal.predicate.self_ty())], + ); + ecx.add_goal(goal.with(tcx, sized_predicate)); + tcx.types.unit + } - ty::Tuple(elements) => match elements.last() { + ty::Adt(def, substs) if def.is_struct() => { + match def.non_enum_variant().fields.raw.last() { None => tcx.types.unit, - Some(&self_ty) => { + Some(field_def) => { + let self_ty = field_def.ty(tcx, substs); ecx.add_goal(goal.with( tcx, ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)), @@ -399,21 +377,35 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { return ecx .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); } - }, - - ty::Infer( - ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_), - ) - | ty::Bound(..) => bug!( - "unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`", - goal.predicate.self_ty() - ), - }; + } + } + ty::Adt(_, _) => tcx.types.unit, - ecx.eq(goal.param_env, goal.predicate.term, metadata_ty.into()) - .expect("expected goal term to be fully unconstrained"); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) + ty::Tuple(elements) => match elements.last() { + None => tcx.types.unit, + Some(&self_ty) => { + ecx.add_goal(goal.with( + tcx, + ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)), + )); + return ecx + .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); + } + }, + + ty::Infer( + ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_), + ) + | ty::Bound(..) => bug!( + "unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`", + goal.predicate.self_ty() + ), + }; + + ecx.eq(goal.param_env, goal.predicate.term, metadata_ty.into()) + .expect("expected goal term to be fully unconstrained"); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } fn consider_builtin_future_candidate( @@ -548,11 +540,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ), }; - ecx.probe(|r| CandidateKind::Candidate { - name: "builtin discriminant kind".into(), - result: *r, - }) - .enter(|ecx| { + ecx.probe_candidate("builtin discriminant kind").enter(|ecx| { ecx.eq(goal.param_env, goal.predicate.term, discriminant_ty.into()) .expect("expected goal term to be fully unconstrained"); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index d167ee46b39..f00456e26df 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -213,7 +213,7 @@ impl<'tcx> SearchGraph<'tcx> { inspect: &mut ProofTreeBuilder<'tcx>, mut loop_body: impl FnMut(&mut Self, &mut ProofTreeBuilder<'tcx>) -> QueryResult<'tcx>, ) -> QueryResult<'tcx> { - if self.should_use_global_cache() { + if self.should_use_global_cache() && inspect.use_global_cache() { if let Some(result) = tcx.new_solver_evaluation_cache.get(&canonical_input, tcx) { debug!(?canonical_input, ?result, "cache hit"); inspect.cache_hit(CacheHit::Global); diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 18fec6d9c89..cd68626bed1 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -6,8 +6,8 @@ use rustc_hir::def_id::DefId; use rustc_hir::{LangItem, Movability}; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::util::supertraits; -use rustc_middle::traits::solve::inspect::CandidateKind; use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult}; +use rustc_middle::traits::Reveal; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; use rustc_middle::ty::{TraitPredicate, TypeVisitableExt}; @@ -62,7 +62,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { }, }; - ecx.probe(|r| CandidateKind::Candidate { name: "impl".into(), result: *r }).enter(|ecx| { + ecx.probe_candidate("impl").enter(|ecx| { let impl_substs = ecx.fresh_substs_for_item(impl_def_id); let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); @@ -90,16 +90,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { && trait_clause.polarity() == goal.predicate.polarity { // FIXME: Constness - ecx.probe(|r| CandidateKind::Candidate { name: "assumption".into(), result: *r }) - .enter(|ecx| { - let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause); - ecx.eq( - goal.param_env, - goal.predicate.trait_ref, - assumption_trait_pred.trait_ref, - )?; - then(ecx) - }) + ecx.probe_candidate("assumption").enter(|ecx| { + let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause); + ecx.eq( + goal.param_env, + goal.predicate.trait_ref, + assumption_trait_pred.trait_ref, + )?; + then(ecx) + }) } else { Err(NoSolution) } @@ -120,6 +119,32 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { return result; } + // Don't call `type_of` on a local TAIT that's in the defining scope, + // since that may require calling `typeck` on the same item we're + // currently type checking, which will result in a fatal cycle that + // ideally we want to avoid, since we can make progress on this goal + // via an alias bound or a locally-inferred hidden type instead. + // + // Also, don't call `type_of` on a TAIT in `Reveal::All` mode, since + // we already normalize the self type in + // `assemble_candidates_after_normalizing_self_ty`, and we'd + // just be registering an identical candidate here. + // + // Returning `Err(NoSolution)` here is ok in `SolverMode::Coherence` + // since we'll always be registering an ambiguous candidate in + // `assemble_candidates_after_normalizing_self_ty` due to normalizing + // the TAIT. + if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() { + if matches!(goal.param_env.reveal(), Reveal::All) + || opaque_ty + .def_id + .as_local() + .is_some_and(|def_id| ecx.can_define_opaque_ty(def_id)) + { + return Err(NoSolution); + } + } + ecx.probe_and_evaluate_goal_for_constituent_tys( goal, structural_traits::instantiate_constituent_tys_for_auto_trait, @@ -136,15 +161,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let tcx = ecx.tcx(); - ecx.probe(|r| CandidateKind::Candidate { name: "trait alias".into(), result: *r }).enter( - |ecx| { - let nested_obligations = tcx - .predicates_of(goal.predicate.def_id()) - .instantiate(tcx, goal.predicate.trait_ref.substs); - ecx.add_goals(nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p))); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }, - ) + ecx.probe_candidate("trait alias").enter(|ecx| { + let nested_obligations = tcx + .predicates_of(goal.predicate.def_id()) + .instantiate(tcx, goal.predicate.trait_ref.substs); + ecx.add_goals(nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p))); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } fn consider_builtin_sized_candidate( @@ -350,115 +373,109 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { if b_ty.is_ty_var() { return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); } - ecx.probe(|r| CandidateKind::Candidate { name: "builtin unsize".into(), result: *r }).enter( - |ecx| { - match (a_ty.kind(), b_ty.kind()) { - // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b` - (&ty::Dynamic(_, _, ty::Dyn), &ty::Dynamic(_, _, ty::Dyn)) => { - // Dyn upcasting is handled separately, since due to upcasting, - // when there are two supertraits that differ by substs, we - // may return more than one query response. - Err(NoSolution) + ecx.probe_candidate("builtin unsize").enter(|ecx| { + match (a_ty.kind(), b_ty.kind()) { + // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b` + (&ty::Dynamic(_, _, ty::Dyn), &ty::Dynamic(_, _, ty::Dyn)) => { + // Dyn upcasting is handled separately, since due to upcasting, + // when there are two supertraits that differ by substs, we + // may return more than one query response. + Err(NoSolution) + } + // `T` -> `dyn Trait` unsizing + (_, &ty::Dynamic(data, region, ty::Dyn)) => { + // Can only unsize to an object-safe type + if data + .principal_def_id() + .is_some_and(|def_id| !tcx.check_is_object_safe(def_id)) + { + return Err(NoSolution); } - // `T` -> `dyn Trait` unsizing - (_, &ty::Dynamic(data, region, ty::Dyn)) => { - // Can only unsize to an object-safe type - if data - .principal_def_id() - .is_some_and(|def_id| !tcx.check_is_object_safe(def_id)) - { - return Err(NoSolution); - } - - let Some(sized_def_id) = tcx.lang_items().sized_trait() else { + + let Some(sized_def_id) = tcx.lang_items().sized_trait() else { return Err(NoSolution); }; - // Check that the type implements all of the predicates of the def-id. - // (i.e. the principal, all of the associated types match, and any auto traits) - ecx.add_goals( - data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))), - ); - // The type must be Sized to be unsized. - ecx.add_goal(goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty]))); - // The type must outlive the lifetime of the `dyn` we're unsizing into. - ecx.add_goal( - goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region))), - ); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } - // `[T; n]` -> `[T]` unsizing - (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => { - // We just require that the element type stays the same - ecx.eq(goal.param_env, a_elem_ty, b_elem_ty)?; - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } - // Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>` - (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs)) - if a_def.is_struct() && a_def.did() == b_def.did() => - { - let unsizing_params = tcx.unsizing_params_for_adt(a_def.did()); - // We must be unsizing some type parameters. This also implies - // that the struct has a tail field. - if unsizing_params.is_empty() { - return Err(NoSolution); - } - - let tail_field = a_def - .non_enum_variant() - .fields - .raw - .last() - .expect("expected unsized ADT to have a tail field"); - let tail_field_ty = tcx.type_of(tail_field.did); - - let a_tail_ty = tail_field_ty.subst(tcx, a_substs); - let b_tail_ty = tail_field_ty.subst(tcx, b_substs); - - // Substitute just the unsizing params from B into A. The type after - // this substitution must be equal to B. This is so we don't unsize - // unrelated type parameters. - let new_a_substs = - tcx.mk_substs_from_iter(a_substs.iter().enumerate().map(|(i, a)| { - if unsizing_params.contains(i as u32) { b_substs[i] } else { a } - })); - let unsized_a_ty = tcx.mk_adt(a_def, new_a_substs); - - // Finally, we require that `TailA: Unsize<TailB>` for the tail field - // types. - ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; - ecx.add_goal(goal.with( - tcx, - ty::TraitRef::new(tcx, goal.predicate.def_id(), [a_tail_ty, b_tail_ty]), - )); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } - // Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>` - (&ty::Tuple(a_tys), &ty::Tuple(b_tys)) - if a_tys.len() == b_tys.len() && !a_tys.is_empty() => - { - let (a_last_ty, a_rest_tys) = a_tys.split_last().unwrap(); - let b_last_ty = b_tys.last().unwrap(); - - // Substitute just the tail field of B., and require that they're equal. - let unsized_a_ty = - tcx.mk_tup_from_iter(a_rest_tys.iter().chain([b_last_ty]).copied()); - ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; - - // Similar to ADTs, require that the rest of the fields are equal. - ecx.add_goal(goal.with( - tcx, - ty::TraitRef::new( - tcx, - goal.predicate.def_id(), - [*a_last_ty, *b_last_ty], - ), - )); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + // Check that the type implements all of the predicates of the def-id. + // (i.e. the principal, all of the associated types match, and any auto traits) + ecx.add_goals( + data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))), + ); + // The type must be Sized to be unsized. + ecx.add_goal(goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty]))); + // The type must outlive the lifetime of the `dyn` we're unsizing into. + ecx.add_goal( + goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region))), + ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + // `[T; n]` -> `[T]` unsizing + (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => { + // We just require that the element type stays the same + ecx.eq(goal.param_env, a_elem_ty, b_elem_ty)?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + // Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>` + (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs)) + if a_def.is_struct() && a_def.did() == b_def.did() => + { + let unsizing_params = tcx.unsizing_params_for_adt(a_def.did()); + // We must be unsizing some type parameters. This also implies + // that the struct has a tail field. + if unsizing_params.is_empty() { + return Err(NoSolution); } - _ => Err(NoSolution), + + let tail_field = a_def + .non_enum_variant() + .fields + .raw + .last() + .expect("expected unsized ADT to have a tail field"); + let tail_field_ty = tcx.type_of(tail_field.did); + + let a_tail_ty = tail_field_ty.subst(tcx, a_substs); + let b_tail_ty = tail_field_ty.subst(tcx, b_substs); + + // Substitute just the unsizing params from B into A. The type after + // this substitution must be equal to B. This is so we don't unsize + // unrelated type parameters. + let new_a_substs = + tcx.mk_substs_from_iter(a_substs.iter().enumerate().map(|(i, a)| { + if unsizing_params.contains(i as u32) { b_substs[i] } else { a } + })); + let unsized_a_ty = Ty::new_adt(tcx, a_def, new_a_substs); + + // Finally, we require that `TailA: Unsize<TailB>` for the tail field + // types. + ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; + ecx.add_goal(goal.with( + tcx, + ty::TraitRef::new(tcx, goal.predicate.def_id(), [a_tail_ty, b_tail_ty]), + )); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } - }, - ) + // Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>` + (&ty::Tuple(a_tys), &ty::Tuple(b_tys)) + if a_tys.len() == b_tys.len() && !a_tys.is_empty() => + { + let (a_last_ty, a_rest_tys) = a_tys.split_last().unwrap(); + let b_last_ty = b_tys.last().unwrap(); + + // Substitute just the tail field of B., and require that they're equal. + let unsized_a_ty = + Ty::new_tup_from_iter(tcx, a_rest_tys.iter().chain([b_last_ty]).copied()); + ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; + + // Similar to ADTs, require that the rest of the fields are equal. + ecx.add_goal(goal.with( + tcx, + ty::TraitRef::new(tcx, goal.predicate.def_id(), [*a_last_ty, *b_last_ty]), + )); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + _ => Err(NoSolution), + } + }) } fn consider_builtin_dyn_upcast_candidates( @@ -488,11 +505,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } let mut unsize_dyn_to_principal = |principal: Option<ty::PolyExistentialTraitRef<'tcx>>| { - ecx.probe(|r| CandidateKind::Candidate { - name: "upcast dyn to principle".into(), - result: *r, - }) - .enter(|ecx| -> Result<_, NoSolution> { + ecx.probe_candidate("upcast dyn to principle").enter(|ecx| -> Result<_, NoSolution> { // Require that all of the trait predicates from A match B, except for // the auto traits. We do this by constructing a new A type with B's // auto traits, and equating these types. @@ -509,7 +522,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { .map(ty::Binder::dummy), ); let new_a_data = tcx.mk_poly_existential_predicates_from_iter(new_a_data); - let new_a_ty = tcx.mk_dynamic(new_a_data, b_region, ty::Dyn); + let new_a_ty = Ty::new_dynamic(tcx, new_a_data, b_region, ty::Dyn); // We also require that A's lifetime outlives B's lifetime. ecx.eq(goal.param_env, new_a_ty, b_ty)?; @@ -714,21 +727,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, TraitPredicate<'tcx>>, constituent_tys: impl Fn(&EvalCtxt<'_, 'tcx>, Ty<'tcx>) -> Result<Vec<Ty<'tcx>>, NoSolution>, ) -> QueryResult<'tcx> { - self.probe(|r| CandidateKind::Candidate { name: "constituent tys".into(), result: *r }) - .enter(|ecx| { - ecx.add_goals( - constituent_tys(ecx, goal.predicate.self_ty())? - .into_iter() - .map(|ty| { - goal.with( - ecx.tcx(), - ty::Binder::dummy(goal.predicate.with_self_ty(ecx.tcx(), ty)), - ) - }) - .collect::<Vec<_>>(), - ); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) + self.probe_candidate("constituent tys").enter(|ecx| { + ecx.add_goals( + constituent_tys(ecx, goal.predicate.self_ty())? + .into_iter() + .map(|ty| { + goal.with( + ecx.tcx(), + ty::Binder::dummy(goal.predicate.with_self_ty(ecx.tcx(), ty)), + ) + }) + .collect::<Vec<_>>(), + ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } #[instrument(level = "debug", skip(self))] diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index fb6bf7211b9..4296ed64cf0 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -794,7 +794,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { unevaluated, Some(obligation.cause.span), ) { - Ok(Some(valtree)) => Ok(selcx.tcx().mk_const(valtree, c.ty())), + Ok(Some(valtree)) => Ok(ty::Const::new_value(selcx.tcx(),valtree, c.ty())), Ok(None) => { let tcx = self.tcx; let reported = @@ -836,9 +836,6 @@ impl<'tcx> AutoTraitFinder<'tcx> { // FIXME(generic_const_exprs): you can absolutely add this as a where clauses | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::Coerce(..) => {} - ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => { - bug!("predicate should only exist in the environment: {bound_predicate:?}") - } ty::PredicateKind::Ambiguous => return false, }; } diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs deleted file mode 100644 index 3ecae429c59..00000000000 --- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs +++ /dev/null @@ -1,149 +0,0 @@ -//! Defines a Chalk-based `TraitEngine` - -use crate::infer::canonical::OriginalQueryValues; -use crate::infer::InferCtxt; -use crate::traits::query::NoSolution; -use crate::traits::{ - ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, PredicateObligation, - SelectionError, TraitEngine, -}; -use rustc_data_structures::fx::FxIndexSet; -use rustc_middle::ty::TypeVisitableExt; - -pub struct FulfillmentContext<'tcx> { - obligations: FxIndexSet<PredicateObligation<'tcx>>, - - /// The snapshot in which this context was created. Using the context - /// outside of this snapshot leads to subtle bugs if the snapshot - /// gets rolled back. Because of this we explicitly check that we only - /// use the context in exactly this snapshot. - usable_in_snapshot: usize, -} - -impl<'tcx> FulfillmentContext<'tcx> { - pub(super) fn new(infcx: &InferCtxt<'tcx>) -> Self { - FulfillmentContext { - obligations: FxIndexSet::default(), - usable_in_snapshot: infcx.num_open_snapshots(), - } - } -} - -impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { - fn register_predicate_obligation( - &mut self, - infcx: &InferCtxt<'tcx>, - obligation: PredicateObligation<'tcx>, - ) { - assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots()); - let obligation = infcx.resolve_vars_if_possible(obligation); - - self.obligations.insert(obligation); - } - - fn collect_remaining_errors( - &mut self, - _infcx: &InferCtxt<'tcx>, - ) -> Vec<FulfillmentError<'tcx>> { - // any remaining obligations are errors - self.obligations - .iter() - .map(|obligation| FulfillmentError { - obligation: obligation.clone(), - code: FulfillmentErrorCode::CodeAmbiguity { overflow: false }, - // FIXME - does Chalk have a notation of 'root obligation'? - // This is just for diagnostics, so it's okay if this is wrong - root_obligation: obligation.clone(), - }) - .collect() - } - - fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { - assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots()); - - let mut errors = Vec::new(); - let mut next_round = FxIndexSet::default(); - let mut making_progress; - - loop { - making_progress = false; - - // We iterate over all obligations, and record if we are able - // to unambiguously prove at least one obligation. - for obligation in self.obligations.drain(..) { - let obligation = infcx.resolve_vars_if_possible(obligation); - let environment = obligation.param_env.caller_bounds(); - let goal = ChalkEnvironmentAndGoal { environment, goal: obligation.predicate }; - let mut orig_values = OriginalQueryValues::default(); - if goal.references_error() { - continue; - } - - let canonical_goal = - infcx.canonicalize_query_preserving_universes(goal, &mut orig_values); - - match infcx.tcx.evaluate_goal(canonical_goal) { - Ok(response) => { - if response.is_proven() { - making_progress = true; - - match infcx.instantiate_query_response_and_region_obligations( - &obligation.cause, - obligation.param_env, - &orig_values, - &response, - ) { - Ok(infer_ok) => { - next_round.extend(infer_ok.obligations.into_iter().map( - |obligation| infcx.resolve_vars_if_possible(obligation), - )) - } - - Err(_err) => errors.push(FulfillmentError { - obligation: obligation.clone(), - code: FulfillmentErrorCode::CodeSelectionError( - SelectionError::Unimplemented, - ), - // FIXME - does Chalk have a notation of 'root obligation'? - // This is just for diagnostics, so it's okay if this is wrong - root_obligation: obligation, - }), - } - } else { - // Ambiguous: retry at next round. - next_round.insert(obligation); - } - } - - Err(NoSolution) => errors.push(FulfillmentError { - obligation: obligation.clone(), - code: FulfillmentErrorCode::CodeSelectionError( - SelectionError::Unimplemented, - ), - // FIXME - does Chalk have a notation of 'root obligation'? - // This is just for diagnostics, so it's okay if this is wrong - root_obligation: obligation, - }), - } - } - next_round = std::mem::replace(&mut self.obligations, next_round); - - if !making_progress { - break; - } - } - - errors - } - - fn drain_unstalled_obligations( - &mut self, - _: &InferCtxt<'tcx>, - ) -> Vec<PredicateObligation<'tcx>> { - unimplemented!() - } - - fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { - self.obligations.iter().cloned().collect() - } -} diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 9e1332c1c81..1b1285e1b46 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -30,6 +30,7 @@ use std::fmt::Debug; use std::iter; use std::ops::ControlFlow; +use super::query::evaluate_obligation::InferCtxtExt; use super::NormalizeExt; /// Whether we do the orphan check relative to this crate or @@ -290,6 +291,20 @@ fn impl_intersection_has_impossible_obligation<'cx, 'tcx>( ) -> bool { let infcx = selcx.infcx; + let obligation_guaranteed_to_fail = move |obligation: &PredicateObligation<'tcx>| { + if infcx.next_trait_solver() { + infcx.evaluate_obligation(obligation).map_or(false, |result| !result.may_apply()) + } else { + // We use `evaluate_root_obligation` to correctly track + // intercrate ambiguity clauses. We do not need this in the + // new solver. + selcx.evaluate_root_obligation(obligation).map_or( + false, // Overflow has occurred, and treat the obligation as possibly holding. + |result| !result.may_apply(), + ) + } + }; + let opt_failing_obligation = [&impl1_header.predicates, &impl2_header.predicates] .into_iter() .flatten() @@ -297,12 +312,7 @@ fn impl_intersection_has_impossible_obligation<'cx, 'tcx>( Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, predicate) }) .chain(obligations) - .find(|o| { - selcx.evaluate_root_obligation(o).map_or( - false, // Overflow has occurred, and treat the obligation as possibly holding. - |result| !result.may_apply(), - ) - }); + .find(obligation_guaranteed_to_fail); if let Some(failing_obligation) = opt_failing_obligation { debug!("overlap: obligation unsatisfiable {:?}", failing_obligation); @@ -427,7 +437,11 @@ fn prove_negated_obligation<'tcx>( let body_def_id = body_def_id.as_local().unwrap_or(CRATE_DEF_ID); let ocx = ObligationCtxt::new(&infcx); - let wf_tys = ocx.assumed_wf_types(param_env, DUMMY_SP, body_def_id); + let Ok(wf_tys) = ocx.assumed_wf_types(param_env, body_def_id) + else { + return false; + }; + let outlives_env = OutlivesEnvironment::with_bounds( param_env, infcx.implied_bounds_tys(param_env, body_def_id, wf_tys), diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index faa675054b7..61f693e1bd1 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -1,9 +1,10 @@ use std::cell::RefCell; use std::fmt::Debug; +use super::FulfillmentContext; use super::TraitEngine; -use super::{ChalkFulfillmentContext, FulfillmentContext}; use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt; +use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::NormalizeExt; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::ErrorGuaranteed; @@ -24,7 +25,6 @@ use rustc_middle::ty::ToPredicate; use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::config::TraitSolver; -use rustc_span::Span; pub trait TraitEngineExt<'tcx> { fn new(infcx: &InferCtxt<'tcx>) -> Box<Self>; @@ -39,7 +39,6 @@ impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { (TraitSolver::Next | TraitSolver::NextCoherence, true) => { Box::new(NextFulfillmentCtxt::new(infcx)) } - (TraitSolver::Chalk, false) => Box::new(ChalkFulfillmentContext::new(infcx)), _ => bug!( "incompatible combination of -Ztrait-solver flag ({:?}) and InferCtxt::next_trait_solver ({:?})", infcx.tcx.sess.opts.unstable_opts.trait_solver, @@ -198,17 +197,24 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { } } + pub fn assumed_wf_types_and_report_errors( + &self, + param_env: ty::ParamEnv<'tcx>, + def_id: LocalDefId, + ) -> Result<FxIndexSet<Ty<'tcx>>, ErrorGuaranteed> { + self.assumed_wf_types(param_env, def_id) + .map_err(|errors| self.infcx.err_ctxt().report_fulfillment_errors(&errors)) + } + pub fn assumed_wf_types( &self, param_env: ty::ParamEnv<'tcx>, - span: Span, def_id: LocalDefId, - ) -> FxIndexSet<Ty<'tcx>> { + ) -> Result<FxIndexSet<Ty<'tcx>>, Vec<FulfillmentError<'tcx>>> { let tcx = self.infcx.tcx; - let assumed_wf_types = tcx.assumed_wf_types(def_id); let mut implied_bounds = FxIndexSet::default(); - let cause = ObligationCause::misc(span, def_id); - for ty in assumed_wf_types { + let mut errors = Vec::new(); + for &(ty, span) in tcx.assumed_wf_types(def_id) { // FIXME(@lcnr): rustc currently does not check wf for types // pre-normalization, meaning that implied bounds are sometimes // incorrect. See #100910 for more details. @@ -221,10 +227,19 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { // sound and then uncomment this line again. // implied_bounds.insert(ty); - let normalized = self.normalize(&cause, param_env, ty); - implied_bounds.insert(normalized); + let cause = ObligationCause::misc(span, def_id); + match self + .infcx + .at(&cause, param_env) + .deeply_normalize(ty, &mut **self.engine.borrow_mut()) + { + // Insert well-formed types, ignoring duplicates. + Ok(normalized) => drop(implied_bounds.insert(normalized)), + Err(normalization_errors) => errors.extend(normalization_errors), + }; } - implied_bounds + + if errors.is_empty() { Ok(implied_bounds) } else { Err(errors) } } pub fn make_canonicalized_query_response<T>( diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index f7670d51bdc..5b875e19996 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -10,6 +10,7 @@ use super::{ use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{self, InferCtxt}; +use crate::solve::{GenerateProofTree, InferCtxtEvalExt, UseGlobalCache}; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::query::normalize::QueryNormalizeExt as _; use crate::traits::specialize::to_pretty_impl_header; @@ -28,7 +29,8 @@ use rustc_hir::{GenericParam, Item, Node}; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::{InferOk, TypeTrace}; use rustc_middle::traits::select::OverflowError; -use rustc_middle::traits::SelectionOutputTypeParameterMismatch; +use rustc_middle::traits::solve::Goal; +use rustc_middle::traits::{DefiningAnchor, SelectionOutputTypeParameterMismatch}; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; @@ -37,13 +39,14 @@ use rustc_middle::ty::{ self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitableExt, }; -use rustc_session::config::TraitSolver; +use rustc_session::config::{DumpSolverProofTree, TraitSolver}; use rustc_session::Limit; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::symbol::sym; use rustc_span::{ExpnKind, Span, DUMMY_SP}; use std::borrow::Cow; use std::fmt; +use std::io::Write; use std::iter; use std::ops::ControlFlow; use suggestions::TypeErrCtxtExt as _; @@ -630,6 +633,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { error: &SelectionError<'tcx>, ) { let tcx = self.tcx; + + if tcx.sess.opts.unstable_opts.dump_solver_proof_tree == DumpSolverProofTree::OnError { + dump_proof_tree(root_obligation, self.infcx); + } + let mut span = obligation.cause.span; // FIXME: statically guarantee this by tainting after the diagnostic is emitted self.set_tainted_by_errors( @@ -966,7 +974,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { && self.fallback_has_occurred { let predicate = trait_predicate.map_bound(|trait_pred| { - trait_pred.with_self_ty(self.tcx, self.tcx.mk_unit()) + trait_pred.with_self_ty(self.tcx, Ty::new_unit(self.tcx)) }); let unit_obligation = obligation.with(tcx, predicate); if self.predicate_may_hold(&unit_obligation) { @@ -1059,7 +1067,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // (which may fail). span_bug!(span, "WF predicate not satisfied for {:?}", ty); } - TraitSolver::Chalk | TraitSolver::Next | TraitSolver::NextCoherence => { + TraitSolver::Next | TraitSolver::NextCoherence => { // FIXME: we'll need a better message which takes into account // which bounds actually failed to hold. self.tcx.sess.struct_span_err( @@ -1094,13 +1102,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::PredicateKind::Ambiguous => span_bug!(span, "ambiguous"), - ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => { - span_bug!( - span, - "TypeWellFormedFromEnv predicate should only exist in the environment" - ) - } - ty::PredicateKind::AliasRelate(..) => span_bug!( span, "AliasRelate predicate should never be the predicate cause of a SelectionError" @@ -1151,6 +1152,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } + SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id) => self.report_opaque_type_auto_trait_leakage( + &obligation, + def_id, + ), + TraitNotObjectSafe(did) => { let violations = self.tcx.object_safety_violations(did); report_object_safety_error(self.tcx, span, did, violations) @@ -1169,16 +1175,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } // Already reported in the query. - SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(_)) => { - // FIXME(eddyb) remove this once `ErrorGuaranteed` becomes a proof token. - self.tcx.sess.delay_span_bug(span, "`ErrorGuaranteed` without an error"); - return; - } + SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(_)) | // Already reported. - Overflow(OverflowError::Error(_)) => { - self.tcx.sess.delay_span_bug(span, "`OverflowError` has been reported"); - return; - } + Overflow(OverflowError::Error(_)) => return, + Overflow(_) => { bug!("overflow should be handled before the `report_selection_error` path"); } @@ -1470,6 +1470,12 @@ trait InferCtxtPrivExt<'tcx> { terr: TypeError<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; + fn report_opaque_type_auto_trait_leakage( + &self, + obligation: &PredicateObligation<'tcx>, + def_id: DefId, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; + fn report_type_parameter_mismatch_error( &self, obligation: &PredicateObligation<'tcx>, @@ -1529,6 +1535,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { #[instrument(skip(self), level = "debug")] fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) { + if self.tcx.sess.opts.unstable_opts.dump_solver_proof_tree == DumpSolverProofTree::OnError { + dump_proof_tree(&error.root_obligation, self.infcx); + } + match error.code { FulfillmentErrorCode::CodeSelectionError(ref selection_error) => { self.report_selection_error( @@ -1615,20 +1625,21 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { bound_predicate.rebind(data), ); let unnormalized_term = match data.term.unpack() { - ty::TermKind::Ty(_) => self - .tcx - .mk_projection(data.projection_ty.def_id, data.projection_ty.substs) - .into(), - ty::TermKind::Const(ct) => self - .tcx - .mk_const( - ty::UnevaluatedConst { - def: data.projection_ty.def_id, - substs: data.projection_ty.substs, - }, - ct.ty(), - ) - .into(), + ty::TermKind::Ty(_) => Ty::new_projection( + self.tcx, + data.projection_ty.def_id, + data.projection_ty.substs, + ) + .into(), + ty::TermKind::Const(ct) => ty::Const::new_unevaluated( + self.tcx, + ty::UnevaluatedConst { + def: data.projection_ty.def_id, + substs: data.projection_ty.substs, + }, + ct.ty(), + ) + .into(), }; let normalized_term = ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term); @@ -2642,11 +2653,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Param(ty::ParamTy { name, .. }) = *ty.kind() { + if let ty::Param(_) = *ty.kind() { let infcx = self.infcx; *self.var_map.entry(ty).or_insert_with(|| { infcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeParameterDefinition(name, None), + kind: TypeVariableOriginKind::MiscVariable, span: DUMMY_SP, }) }) @@ -3188,6 +3199,39 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) } + fn report_opaque_type_auto_trait_leakage( + &self, + obligation: &PredicateObligation<'tcx>, + def_id: DefId, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + let name = match self.tcx.opaque_type_origin(def_id.expect_local()) { + hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => { + format!("opaque type") + } + hir::OpaqueTyOrigin::TyAlias { .. } => { + format!("`{}`", self.tcx.def_path_debug_str(def_id)) + } + }; + let mut err = self.tcx.sess.struct_span_err( + obligation.cause.span, + format!("cannot check whether the hidden type of {name} satisfies auto traits"), + ); + err.span_note(self.tcx.def_span(def_id), "opaque type is declared here"); + match self.defining_use_anchor { + DefiningAnchor::Bubble | DefiningAnchor::Error => {} + DefiningAnchor::Bind(bind) => { + err.span_note( + self.tcx.def_ident_span(bind).unwrap_or_else(|| self.tcx.def_span(bind)), + "this item depends on auto traits of the hidden type, \ + but may also be registering the hidden type. \ + This is not supported right now. \ + You can try moving the opaque type and the item that actually registers a hidden type into a new submodule".to_string(), + ); + } + }; + err + } + fn report_type_parameter_mismatch_error( &self, obligation: &PredicateObligation<'tcx>, @@ -3499,3 +3543,16 @@ pub enum DefIdOrName { DefId(DefId), Name(&'static str), } + +pub fn dump_proof_tree<'tcx>(o: &Obligation<'tcx, ty::Predicate<'tcx>>, infcx: &InferCtxt<'tcx>) { + infcx.probe(|_| { + let goal = Goal { predicate: o.predicate, param_env: o.param_env }; + let tree = infcx + .evaluate_root_goal(goal, GenerateProofTree::Yes(UseGlobalCache::No)) + .1 + .expect("proof tree should have been generated"); + let mut lock = std::io::stdout().lock(); + let _ = lock.write_fmt(format_args!("{tree:?}")); + let _ = lock.flush(); + }); +} diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 10bd027b684..1e4d30f48b2 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -278,7 +278,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]` if let ty::Array(aty, len) = self_ty.kind() { flags.push((sym::_Self, Some("[]".to_string()))); - let len = len.kind().try_to_value().and_then(|v| v.try_to_target_usize(self.tcx)); + let len = len.try_to_value().and_then(|v| v.try_to_target_usize(self.tcx)); flags.push((sym::_Self, Some(format!("[{}; _]", aty)))); if let Some(n) = len { flags.push((sym::_Self, Some(format!("[{}; {}]", aty, n)))); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 619a099fcb5..9ac1ba0275c 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -786,7 +786,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let Some(steps) = autoderef.into_iter().enumerate().find_map(|(steps, (ty, obligations))| { // Re-add the `&` - let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl }); + let ty = Ty::new_ref(self.tcx, region, TypeAndMut { ty, mutbl }); // Remapping bound vars here let real_trait_pred_and_ty = @@ -1298,13 +1298,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| { ( trait_pred, - self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()), + Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, trait_pred.self_ty()), ) }); let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| { ( trait_pred, - self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()), + Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, trait_pred.self_ty()), ) }); @@ -1465,7 +1465,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) { let ty::Ref(_, object_ty, hir::Mutability::Not) = target_ty.kind() else { return; }; let ty::Dynamic(predicates, _, ty::Dyn) = object_ty.kind() else { return; }; - let self_ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, self_ty); + let self_ref_ty = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, self_ty); for predicate in predicates.iter() { if !self.predicate_must_hold_modulo_regions( @@ -1706,8 +1706,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let ty::Ref(region, t_type, mutability) = *trait_pred.skip_binder().self_ty().kind() { let suggested_ty = match mutability { - hir::Mutability::Mut => self.tcx.mk_imm_ref(region, t_type), - hir::Mutability::Not => self.tcx.mk_mut_ref(region, t_type), + hir::Mutability::Mut => Ty::new_imm_ref(self.tcx, region, t_type), + hir::Mutability::Not => Ty::new_mut_ref(self.tcx, region, t_type), }; // Remapping bound vars here @@ -1951,7 +1951,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ), }; - infcx.tcx.mk_fn_ptr(trait_ref.rebind(sig)) + Ty::new_fn_ptr(infcx.tcx, trait_ref.rebind(sig)) } let argument_kind = match expected.skip_binder().self_ty().kind() { @@ -3347,7 +3347,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; // `<T as Future>::Output` let projection_ty = trait_pred.map_bound(|trait_pred| { - self.tcx.mk_projection( + Ty::new_projection( + self.tcx, item_def_id, // Future::Output has no substs [trait_pred.self_ty()], @@ -3501,7 +3502,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { { if let hir::Expr { kind: hir::ExprKind::Block(..), .. } = expr { let expr = expr.peel_blocks(); - let ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error_misc()); + let ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx,)); let span = expr.span; if Some(span) != err.span.primary_span() { err.span_label( @@ -3555,7 +3556,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { { type_diffs = vec![ Sorts(ty::error::ExpectedFound { - expected: self.tcx.mk_alias(ty::Projection, where_pred.skip_binder().projection_ty), + expected: Ty::new_alias(self.tcx,ty::Projection, where_pred.skip_binder().projection_ty), found, }), ]; @@ -3646,7 +3647,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Extract `<U as Deref>::Target` assoc type and check that it is `T` && let Some(deref_target_did) = tcx.lang_items().deref_target() - && let projection = tcx.mk_projection(deref_target_did, tcx.mk_substs(&[ty::GenericArg::from(found_ty)])) + && let projection = Ty::new_projection(tcx,deref_target_did, tcx.mk_substs(&[ty::GenericArg::from(found_ty)])) && let InferOk { value: deref_target, obligations } = infcx.at(&ObligationCause::dummy(), param_env).normalize(projection) && obligations.iter().all(|obligation| infcx.predicate_must_hold_modulo_regions(obligation)) && infcx.can_eq(param_env, deref_target, target_ty) @@ -3693,7 +3694,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut assocs = vec![]; let mut expr = expr; let mut prev_ty = self.resolve_vars_if_possible( - typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error_misc()), + typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)), ); while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, span) = expr.kind { // Point at every method call in the chain with the resulting type. @@ -3704,7 +3705,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.probe_assoc_types_at_expr(&type_diffs, span, prev_ty, expr.hir_id, param_env); assocs.push(assocs_in_this_method); prev_ty = self.resolve_vars_if_possible( - typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error_misc()), + typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)), ); if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind @@ -3722,7 +3723,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let hir::Node::Param(param) = parent { // ...and it is a an fn argument. let prev_ty = self.resolve_vars_if_possible( - typeck_results.node_type_opt(param.hir_id).unwrap_or(tcx.ty_error_misc()), + typeck_results.node_type_opt(param.hir_id).unwrap_or(Ty::new_misc_error(tcx,)), ); let assocs_in_this_method = self.probe_assoc_types_at_expr(&type_diffs, param.ty_span, prev_ty, param.hir_id, param_env); if assocs_in_this_method.iter().any(|a| a.is_some()) { diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index e3472a1c4c1..2d8c260126d 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -359,9 +359,6 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ProcessResult::Changed(mk_pending(vec![obligation.with(infcx.tcx, pred)])) } ty::PredicateKind::Ambiguous => ProcessResult::Unchanged, - ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => { - bug!("TypeWellFormedFromEnv is only used for Chalk") - } ty::PredicateKind::AliasRelate(..) => { bug!("AliasRelate is only used for new solver") } @@ -531,7 +528,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { debug!("equating consts:\nc1= {:?}\nc2= {:?}", c1, c2); use rustc_hir::def::DefKind; - use ty::ConstKind::Unevaluated; + use ty::Unevaluated; match (c1.kind(), c2.kind()) { (Unevaluated(a), Unevaluated(b)) if a.def == b.def && tcx.def_kind(a.def) == DefKind::AssocConst => @@ -627,9 +624,6 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } ty::PredicateKind::Ambiguous => ProcessResult::Unchanged, - ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => { - bug!("TypeWellFormedFromEnv is only used for Chalk") - } ty::PredicateKind::AliasRelate(..) => { bug!("AliasRelate is only used for new solver") } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 5dc5ddbddbd..e2ee347b639 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -3,7 +3,6 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html pub mod auto_trait; -mod chalk_fulfill; pub(crate) mod coherence; pub mod const_evaluatable; mod engine; @@ -40,6 +39,8 @@ use rustc_span::Span; use std::fmt::Debug; use std::ops::ControlFlow; +pub(crate) use self::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer}; + pub use self::FulfillmentErrorCode::*; pub use self::ImplSource::*; pub use self::ObligationCauseCode::*; @@ -72,8 +73,6 @@ pub use self::util::{ pub use self::util::{expand_trait_aliases, TraitAliasExpander}; pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices}; -pub use self::chalk_fulfill::FulfillmentContext as ChalkFulfillmentContext; - pub use rustc_infer::traits::*; /// Whether to skip the leak check, as part of a future compatibility warning step. @@ -407,7 +406,12 @@ pub fn normalize_param_env_or_error<'tcx>( ) } -/// Normalize a type and process all resulting obligations, returning any errors +/// Normalize a type and process all resulting obligations, returning any errors. +/// +/// FIXME(-Ztrait-solver=next): This should be replaced by `At::deeply_normalize` +/// which has the same behavior with the new solver. Because using a separate +/// fulfillment context worsens caching in the old solver, `At::deeply_normalize` +/// is still lazy with the old solver as it otherwise negatively impacts perf. #[instrument(skip_all)] pub fn fully_normalize<'tcx, T>( infcx: &InferCtxt<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 78270b7d535..c31944c162e 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -101,7 +101,7 @@ pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::A debug_assert!(tcx.generics_of(trait_def_id).has_self); debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method); // Any method that has a `Self: Sized` bound cannot be called. - if generics_require_sized_self(tcx, method.def_id) { + if tcx.generics_require_sized_self(method.def_id) { return false; } @@ -311,7 +311,7 @@ fn predicate_references_self<'tcx>( | ty::ClauseKind::RegionOutlives(..) // FIXME(generic_const_exprs): this can mention `Self` | ty::ClauseKind::ConstEvaluatable(..) - | ty::ClauseKind::TypeWellFormedFromEnv(_) => None, + => None, } } @@ -331,7 +331,7 @@ fn super_predicates_have_non_lifetime_binders( } fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { - generics_require_sized_self(tcx, trait_def_id) + tcx.generics_require_sized_self(trait_def_id) } fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { @@ -351,8 +351,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::ClauseKind::Projection(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) - | ty::ClauseKind::TypeWellFormedFromEnv(_) => false, + | ty::ClauseKind::ConstEvaluatable(_) => false, }) } @@ -365,7 +364,7 @@ fn object_safety_violation_for_assoc_item( ) -> Option<ObjectSafetyViolation> { // Any item that has a `Self : Sized` requisite is otherwise // exempt from the regulations. - if generics_require_sized_self(tcx, item.def_id) { + if tcx.generics_require_sized_self(item.def_id) { return None; } @@ -510,7 +509,7 @@ fn virtual_call_violation_for_method<'tcx>( // e.g., `Rc<()>` let unit_receiver_ty = - receiver_for_self_ty(tcx, receiver_ty, tcx.mk_unit(), method.def_id); + receiver_for_self_ty(tcx, receiver_ty, Ty::new_unit(tcx), method.def_id); match abi_of_ty(unit_receiver_ty) { Some(Abi::Scalar(..)) => (), @@ -665,7 +664,7 @@ fn object_ty_for_trait<'tcx>( ); debug!(?existential_predicates); - tcx.mk_dynamic(existential_predicates, lifetime, ty::Dyn) + Ty::new_dynamic(tcx, existential_predicates, lifetime, ty::Dyn) } /// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a @@ -733,7 +732,7 @@ fn receiver_is_dispatchable<'tcx>( // FIXME(mikeyhew) this is a total hack. Once object_safe_for_dispatch is stabilized, we can // replace this with `dyn Trait` let unsized_self_ty: Ty<'tcx> = - tcx.mk_ty_param(u32::MAX, Symbol::intern("RustaceansAreAwesome")); + Ty::new_param(tcx, u32::MAX, Symbol::intern("RustaceansAreAwesome")); // `Receiver[Self => U]` let unsized_receiver_ty = @@ -923,5 +922,10 @@ pub fn contains_illegal_impl_trait_in_trait<'tcx>( } pub fn provide(providers: &mut Providers) { - *providers = Providers { object_safety_violations, check_is_object_safe, ..*providers }; + *providers = Providers { + object_safety_violations, + check_is_object_safe, + generics_require_sized_self, + ..*providers + }; } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 8fd77335074..717b35784d8 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -28,7 +28,9 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::at::At; use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_infer::infer::DefineOpaqueTypes; +use rustc_infer::traits::FulfillmentError; use rustc_infer::traits::ObligationCauseCode; +use rustc_infer::traits::TraitEngine; use rustc_middle::traits::select::OverflowError; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable, TypeVisitableExt}; @@ -53,14 +55,55 @@ pub trait NormalizeExt<'tcx> { /// This normalization should be used when the type contains inference variables or the /// projection may be fallible. fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> InferOk<'tcx, T>; + + /// Deeply normalizes `value`, replacing all aliases which can by normalized in + /// the current environment. In the new solver this errors in case normalization + /// fails or is ambiguous. This only normalizes opaque types with `Reveal::All`. + /// + /// In the old solver this simply uses `normalizes` and adds the nested obligations + /// to the `fulfill_cx`. This is necessary as we otherwise end up recomputing the + /// same goals in both a temporary and the shared context which negatively impacts + /// performance as these don't share caching. + /// + /// FIXME(-Ztrait-solver=next): This has the same behavior as `traits::fully_normalize` + /// in the new solver, but because of performance reasons, we currently reuse an + /// existing fulfillment context in the old solver. Once we also eagerly prove goals with + /// the old solver or have removed the old solver, remove `traits::fully_normalize` and + /// rename this function to `At::fully_normalize`. + fn deeply_normalize<T: TypeFoldable<TyCtxt<'tcx>>>( + self, + value: T, + fulfill_cx: &mut dyn TraitEngine<'tcx>, + ) -> Result<T, Vec<FulfillmentError<'tcx>>>; } impl<'tcx> NormalizeExt<'tcx> for At<'_, 'tcx> { fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> InferOk<'tcx, T> { - let mut selcx = SelectionContext::new(self.infcx); - let Normalized { value, obligations } = - normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value); - InferOk { value, obligations } + if self.infcx.next_trait_solver() { + InferOk { value, obligations: Vec::new() } + } else { + let mut selcx = SelectionContext::new(self.infcx); + let Normalized { value, obligations } = + normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value); + InferOk { value, obligations } + } + } + + fn deeply_normalize<T: TypeFoldable<TyCtxt<'tcx>>>( + self, + value: T, + fulfill_cx: &mut dyn TraitEngine<'tcx>, + ) -> Result<T, Vec<FulfillmentError<'tcx>>> { + if self.infcx.next_trait_solver() { + crate::solve::deeply_normalize(self, value) + } else { + let value = self + .normalize(value) + .into_value_registering_obligations(self.infcx, &mut *fulfill_cx); + let errors = fulfill_cx.select_where_possible(self.infcx); + let value = self.infcx.resolve_vars_if_possible(value); + if errors.is_empty() { Ok(value) } else { Err(errors) } + } } } @@ -404,6 +447,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { depth: usize, obligations: &'a mut Vec<PredicateObligation<'tcx>>, ) -> AssocTypeNormalizer<'a, 'b, 'tcx> { + debug_assert!(!selcx.infcx.next_trait_solver()); AssocTypeNormalizer { selcx, param_env, @@ -862,7 +906,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> { let universe = self.universe_for(debruijn); let p = ty::PlaceholderType { universe, bound: bound_ty }; self.mapped_types.insert(p, bound_ty); - self.infcx.tcx.mk_placeholder(p) + Ty::new_placeholder(self.infcx.tcx, p) } _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self), _ => t, @@ -881,7 +925,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> { let universe = self.universe_for(debruijn); let p = ty::PlaceholderConst { universe, bound: bound_const }; self.mapped_consts.insert(p, bound_const); - self.infcx.tcx.mk_const(p, ct.ty()) + ty::Const::new_placeholder(self.infcx.tcx, p, ct.ty()) } _ => ct.super_fold_with(self), } @@ -992,7 +1036,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> { let db = ty::DebruijnIndex::from_usize( self.universe_indices.len() - index + self.current_index.as_usize() - 1, ); - self.interner().mk_bound(db, *replace_var) + Ty::new_bound(self.infcx.tcx, db, *replace_var) } None => ty, } @@ -1016,7 +1060,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> { let db = ty::DebruijnIndex::from_usize( self.universe_indices.len() - index + self.current_index.as_usize() - 1, ); - self.interner().mk_const(ty::ConstKind::Bound(db, *replace_var), ct.ty()) + ty::Const::new_bound(self.infcx.tcx, db, *replace_var, ct.ty()) } None => ct, } @@ -1079,6 +1123,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( obligations: &mut Vec<PredicateObligation<'tcx>>, ) -> Result<Option<Term<'tcx>>, InProgress> { let infcx = selcx.infcx; + debug_assert!(!selcx.infcx.next_trait_solver()); // Don't use the projection cache in intercrate mode - // the `infcx` may be re-used between intercrate in non-intercrate // mode, which could lead to using incorrect cache results. @@ -1395,7 +1440,7 @@ struct Progress<'tcx> { impl<'tcx> Progress<'tcx> { fn error(tcx: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self { - Progress { term: tcx.ty_error(guar).into(), obligations: vec![] } + Progress { term: Ty::new_error(tcx, guar).into(), obligations: vec![] } } fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx>>) -> Self { @@ -1454,19 +1499,22 @@ fn project<'cx, 'tcx>( ProjectionCandidateSet::None => { let tcx = selcx.tcx(); let term = match tcx.def_kind(obligation.predicate.def_id) { - DefKind::AssocTy | DefKind::ImplTraitPlaceholder => tcx - .mk_projection(obligation.predicate.def_id, obligation.predicate.substs) - .into(), - DefKind::AssocConst => tcx - .mk_const( - ty::ConstKind::Unevaluated(ty::UnevaluatedConst::new( - obligation.predicate.def_id, - obligation.predicate.substs, - )), - tcx.type_of(obligation.predicate.def_id) - .subst(tcx, obligation.predicate.substs), - ) - .into(), + DefKind::AssocTy | DefKind::ImplTraitPlaceholder => Ty::new_projection( + tcx, + obligation.predicate.def_id, + obligation.predicate.substs, + ) + .into(), + DefKind::AssocConst => ty::Const::new_unevaluated( + tcx, + ty::UnevaluatedConst::new( + obligation.predicate.def_id, + obligation.predicate.substs, + ), + tcx.type_of(obligation.predicate.def_id) + .subst(tcx, obligation.predicate.substs), + ) + .into(), kind => { bug!("unknown projection def-id: {}", kind.descr(obligation.predicate.def_id)) } @@ -2306,7 +2354,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( obligation, poly_cache_entry, e, ); debug!("confirm_param_env_candidate: {}", msg); - let err = infcx.tcx.ty_error_with_message(obligation.cause.span, msg); + let err = Ty::new_error_with_message(infcx.tcx, obligation.cause.span, msg); Progress { term: err.into(), obligations: vec![] } } } @@ -2338,7 +2386,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( "confirm_impl_candidate: no associated type {:?} for {:?}", assoc_ty.item.name, obligation.predicate ); - return Progress { term: tcx.ty_error_misc().into(), obligations: nested }; + return Progress { term: Ty::new_misc_error(tcx).into(), obligations: nested }; } // If we're trying to normalize `<Vec<u32> as X>::A<S>` using //`impl<T> X for Vec<T> { type A<Y> = Box<Y>; }`, then: @@ -2354,13 +2402,14 @@ fn confirm_impl_candidate<'cx, 'tcx>( let term: ty::EarlyBinder<ty::Term<'tcx>> = if is_const { let did = assoc_ty.item.def_id; let identity_substs = crate::traits::InternalSubsts::identity_for_item(tcx, did); - let kind = ty::ConstKind::Unevaluated(ty::UnevaluatedConst::new(did, identity_substs)); - ty.map_bound(|ty| tcx.mk_const(kind, ty).into()) + let uv = ty::UnevaluatedConst::new(did, identity_substs); + ty.map_bound(|ty| ty::Const::new_unevaluated(tcx, uv, ty).into()) } else { ty.map_bound(|ty| ty.into()) }; if !check_substs_compatible(tcx, assoc_ty.item, substs) { - let err = tcx.ty_error_with_message( + let err = Ty::new_error_with_message( + tcx, obligation.cause.span, "impl item and trait item have different parameters", ); @@ -2387,13 +2436,14 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( // We don't support specialization for RPITITs anyways... yet. // Also don't try to project to an RPITIT that has no value if !leaf_def.is_final() || !leaf_def.item.defaultness(tcx).has_value() { - return Progress { term: tcx.ty_error_misc().into(), obligations }; + return Progress { term: Ty::new_misc_error(tcx).into(), obligations }; } // Use the default `impl Trait` for the trait, e.g., for a default trait body if leaf_def.item.container == ty::AssocItemContainer::TraitContainer { return Progress { - term: tcx.mk_opaque(obligation.predicate.def_id, obligation.predicate.substs).into(), + term: Ty::new_opaque(tcx, obligation.predicate.def_id, obligation.predicate.substs) + .into(), obligations, }; } @@ -2411,7 +2461,8 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( ); if !check_substs_compatible(tcx, leaf_def.item, impl_fn_substs) { - let err = tcx.ty_error_with_message( + let err = Ty::new_error_with_message( + tcx, obligation.cause.span, "impl method and trait method have different parameters", ); @@ -2457,7 +2508,7 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( cause.clone(), obligation.recursion_depth + 1, tcx.collect_return_position_impl_trait_in_trait_tys(impl_fn_def_id).map_or_else( - |guar| tcx.ty_error(guar), + |guar| Ty::new_error(tcx, guar), |tys| tys[&obligation.predicate.def_id].subst(tcx, impl_fn_substs), ), &mut obligations, diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index e29e1b25919..a50644bb709 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -97,6 +97,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { } }) } else { + assert!(!self.intercrate); let c_pred = self.canonicalize_query_keep_static( param_env.and(obligation.predicate), &mut _orig_values, diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index edad519cec2..7fe79fd865c 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -30,7 +30,7 @@ pub trait QueryNormalizeExt<'tcx> { /// /// After codegen, when lifetimes do not matter, it is preferable to instead /// use [`TyCtxt::normalize_erasing_regions`], which wraps this procedure. - fn query_normalize<T>(&self, value: T) -> Result<Normalized<'tcx, T>, NoSolution> + fn query_normalize<T>(self, value: T) -> Result<Normalized<'tcx, T>, NoSolution> where T: TypeFoldable<TyCtxt<'tcx>>; } @@ -49,7 +49,7 @@ impl<'cx, 'tcx> QueryNormalizeExt<'tcx> for At<'cx, 'tcx> { /// normalizing, but for now should be used only when we actually /// know that normalization will succeed, since error reporting /// and other details are still "under development". - fn query_normalize<T>(&self, value: T) -> Result<Normalized<'tcx, T>, NoSolution> + fn query_normalize<T>(self, value: T) -> Result<Normalized<'tcx, T>, NoSolution> where T: TypeFoldable<TyCtxt<'tcx>>, { @@ -60,6 +60,16 @@ impl<'cx, 'tcx> QueryNormalizeExt<'tcx> for At<'cx, 'tcx> { self.param_env, self.cause, ); + + if self.infcx.next_trait_solver() { + match crate::solve::deeply_normalize(self, value) { + Ok(value) => return Ok(Normalized { value, obligations: vec![] }), + Err(_errors) => { + return Err(NoSolution); + } + } + } + if !needs_normalization(&value, self.param_env.reveal()) { return Ok(Normalized { value, obligations: vec![] }); } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index 83d536c9ca5..979498fb6e6 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -1,3 +1,4 @@ +use crate::solve; use crate::traits::query::NoSolution; use crate::traits::wf; use crate::traits::ObligationCtxt; @@ -6,6 +7,7 @@ use rustc_infer::infer::canonical::Canonical; use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_infer::traits::query::OutlivesBound; use rustc_middle::infer::canonical::CanonicalQueryResponse; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::source_map::DUMMY_SP; @@ -134,7 +136,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => {} + => {} // We need to search through *all* WellFormed predicates ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { @@ -164,19 +166,29 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( // We lazily compute the outlives components as // `select_all_or_error` constrains inference variables. - let implied_bounds = outlives_bounds - .into_iter() - .flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() { - ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)], + let mut implied_bounds = Vec::new(); + for ty::OutlivesPredicate(a, r_b) in outlives_bounds { + match a.unpack() { + ty::GenericArgKind::Lifetime(r_a) => { + implied_bounds.push(OutlivesBound::RegionSubRegion(r_b, r_a)) + } ty::GenericArgKind::Type(ty_a) => { - let ty_a = ocx.infcx.resolve_vars_if_possible(ty_a); + let mut ty_a = ocx.infcx.resolve_vars_if_possible(ty_a); + // Need to manually normalize in the new solver as `wf::obligations` does not. + if ocx.infcx.next_trait_solver() { + ty_a = solve::deeply_normalize( + ocx.infcx.at(&ObligationCause::dummy(), param_env), + ty_a, + ) + .map_err(|_errs| NoSolution)?; + } let mut components = smallvec![]; push_outlives_components(tcx, ty_a, &mut components); - implied_bounds_from_components(r_b, components) + implied_bounds.extend(implied_bounds_from_components(r_b, components)) } ty::GenericArgKind::Const(_) => unreachable!(), - }) - .collect(); + } + } Ok(implied_bounds) } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 412b601c966..a0329259705 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -388,7 +388,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// `FnPtr`, when we wanted to report that it doesn't implement `Trait`. #[instrument(level = "trace", skip(self), ret)] fn reject_fn_ptr_impls( - &self, + &mut self, impl_def_id: DefId, obligation: &TraitObligation<'tcx>, impl_self_ty: Ty<'tcx>, @@ -464,7 +464,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) })), ); - if let Ok(r) = self.infcx.evaluate_obligation(&obligation) { + if let Ok(r) = self.evaluate_root_obligation(&obligation) { if !r.may_apply() { return true; } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index cc6521f3b50..21a223135ed 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -16,7 +16,6 @@ use rustc_middle::ty::{ self, Binder, GenericParamDefKind, InternalSubsts, SubstsRef, ToPolyTraitRef, ToPredicate, TraitPredicate, TraitRef, Ty, TyCtxt, TypeVisitableExt, }; -use rustc_session::config::TraitSolver; use rustc_span::def_id::DefId; use crate::traits::project::{normalize_with_depth, normalize_with_depth_to}; @@ -68,7 +67,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } AutoImplCandidate => { - let data = self.confirm_auto_impl_candidate(obligation); + let data = self.confirm_auto_impl_candidate(obligation)?; ImplSource::Builtin(data) } @@ -377,12 +376,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn confirm_auto_impl_candidate( &mut self, obligation: &TraitObligation<'tcx>, - ) -> Vec<PredicateObligation<'tcx>> { + ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { debug!(?obligation, "confirm_auto_impl_candidate"); let self_ty = self.infcx.shallow_resolve(obligation.predicate.self_ty()); - let types = self.constituent_types_for_ty(self_ty); - self.vtable_auto_impl(obligation, obligation.predicate.def_id(), types) + let types = self.constituent_types_for_ty(self_ty)?; + Ok(self.vtable_auto_impl(obligation, obligation.predicate.def_id(), types)) } /// See `confirm_auto_impl_candidate`. @@ -588,7 +587,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let kind = ty::BoundTyKind::Param(param.def_id, param.name); let bound_var = ty::BoundVariableKind::Ty(kind); bound_vars.push(bound_var); - tcx.mk_bound( + Ty::new_bound( + tcx, ty::INNERMOST, ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), @@ -614,11 +614,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { GenericParamDefKind::Const { .. } => { let bound_var = ty::BoundVariableKind::Const; bound_vars.push(bound_var); - tcx.mk_const( - ty::ConstKind::Bound( - ty::INNERMOST, - ty::BoundVar::from_usize(bound_vars.len() - 1), - ), + ty::Const::new_bound( + tcx, + ty::INNERMOST, + ty::BoundVar::from_usize(bound_vars.len() - 1), tcx.type_of(param.def_id) .no_bound_vars() .expect("const parameter types cannot be generic"), @@ -830,13 +829,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations"); - // FIXME: Chalk - if self.tcx().sess.opts.unstable_opts.trait_solver != TraitSolver::Chalk { - nested.push(obligation.with( - self.tcx(), - ty::Binder::dummy(ty::PredicateKind::ClosureKind(closure_def_id, substs, kind)), - )); - } + nested.push(obligation.with( + self.tcx(), + ty::Binder::dummy(ty::PredicateKind::ClosureKind(closure_def_id, substs, kind)), + )); Ok(nested) } @@ -951,7 +947,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map(ty::Binder::dummy), ); let existential_predicates = tcx.mk_poly_existential_predicates_from_iter(iter); - let source_trait = tcx.mk_dynamic(existential_predicates, r_b, repr_a); + let source_trait = Ty::new_dynamic(tcx, existential_predicates, r_b, repr_a); // Require that the traits involved in this upcast are **equal**; // only the **lifetime bound** is changed. @@ -1044,7 +1040,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map(ty::Binder::dummy), ); let existential_predicates = tcx.mk_poly_existential_predicates_from_iter(iter); - let source_trait = tcx.mk_dynamic(existential_predicates, r_b, dyn_a); + let source_trait = Ty::new_dynamic(tcx, existential_predicates, r_b, dyn_a); // Require that the traits involved in this upcast are **equal**; // only the **lifetime bound** is changed. @@ -1162,7 +1158,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let substs = tcx.mk_substs_from_iter(substs_a.iter().enumerate().map(|(i, k)| { if unsizing_params.contains(i as u32) { substs_b[i] } else { k } })); - let new_struct = tcx.mk_adt(def, substs); + let new_struct = Ty::new_adt(tcx, def, substs); let InferOk { obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) @@ -1193,7 +1189,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Check that the source tuple with the target's // last element is equal to the target. let new_tuple = - tcx.mk_tup_from_iter(a_mid.iter().copied().chain(iter::once(b_last))); + Ty::new_tup_from_iter(tcx, a_mid.iter().copied().chain(iter::once(b_last))); let InferOk { obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 7cf8479b803..4a55ceb20a1 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -20,6 +20,7 @@ use super::{ }; use crate::infer::{InferCtxt, InferOk, TypeFreshener}; +use crate::solve::InferCtxtSelectExt; use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::project::try_normalize_with_depth_to; use crate::traits::project::ProjectAndUnifyResult; @@ -33,8 +34,6 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::LateBoundRegionConversionTime; -use rustc_infer::traits::TraitEngine; -use rustc_infer::traits::TraitEngineExt; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::abstract_const::NotConstEvaluatable; @@ -264,6 +263,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, ) -> SelectionResult<'tcx, Selection<'tcx>> { + if self.infcx.next_trait_solver() { + return self.infcx.select_in_new_trait_solver(obligation); + } + let candidate = match self.select_from_obligation(obligation) { Err(SelectionError::Overflow(OverflowError::Canonical)) => { // In standard mode, overflow must have been caught and reported @@ -290,7 +293,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - pub(crate) fn select_from_obligation( + fn select_from_obligation( &mut self, obligation: &TraitObligation<'tcx>, ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { @@ -307,6 +310,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, stack: &TraitObligationStack<'o, 'tcx>, ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { + debug_assert!(!self.infcx.next_trait_solver()); // Watch out for overflow. This intentionally bypasses (and does // not update) the cache. self.check_recursion_limit(&stack.obligation, &stack.obligation)?; @@ -521,21 +525,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Evaluates whether the obligation `obligation` can be satisfied /// and returns an `EvaluationResult`. This is meant for the /// *initial* call. + /// + /// Do not use this directly, use `infcx.evaluate_obligation` instead. pub fn evaluate_root_obligation( &mut self, obligation: &PredicateObligation<'tcx>, ) -> Result<EvaluationResult, OverflowError> { + debug_assert!(!self.infcx.next_trait_solver()); self.evaluation_probe(|this| { let goal = this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env)); - let mut result = if this.infcx.next_trait_solver() { - this.evaluate_predicates_recursively_in_new_solver([obligation.clone()])? - } else { - this.evaluate_predicate_recursively( - TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), - obligation.clone(), - )? - }; + let mut result = this.evaluate_predicate_recursively( + TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), + obligation.clone(), + )?; // If the predicate has done any inference, then downgrade the // result to ambiguous. if this.infcx.shallow_resolve(goal) != goal { @@ -582,42 +585,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { where I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug, { - if self.infcx.next_trait_solver() { - self.evaluate_predicates_recursively_in_new_solver(predicates) - } else { - let mut result = EvaluatedToOk; - for mut obligation in predicates { - obligation.set_depth_from_parent(stack.depth()); - let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; - if let EvaluatedToErr = eval { - // fast-path - EvaluatedToErr is the top of the lattice, - // so we don't need to look on the other predicates. - return Ok(EvaluatedToErr); - } else { - result = cmp::max(result, eval); - } + let mut result = EvaluatedToOk; + for mut obligation in predicates { + obligation.set_depth_from_parent(stack.depth()); + let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; + if let EvaluatedToErr = eval { + // fast-path - EvaluatedToErr is the top of the lattice, + // so we don't need to look on the other predicates. + return Ok(EvaluatedToErr); + } else { + result = cmp::max(result, eval); } - Ok(result) } - } - - /// Evaluates the predicates using the new solver when `-Ztrait-solver=next` is enabled - fn evaluate_predicates_recursively_in_new_solver( - &mut self, - predicates: impl IntoIterator<Item = PredicateObligation<'tcx>>, - ) -> Result<EvaluationResult, OverflowError> { - let mut fulfill_cx = crate::solve::FulfillmentCtxt::new(self.infcx); - fulfill_cx.register_predicate_obligations(self.infcx, predicates); - // True errors - // FIXME(-Ztrait-solver=next): Overflows are reported as ambig here, is that OK? - if !fulfill_cx.select_where_possible(self.infcx).is_empty() { - return Ok(EvaluatedToErr); - } - if !fulfill_cx.select_all_or_error(self.infcx).is_empty() { - return Ok(EvaluatedToAmbig); - } - // Regions and opaques are handled in the `evaluation_probe` by looking at the snapshot - Ok(EvaluatedToOk) + Ok(result) } #[instrument( @@ -631,6 +611,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { previous_stack: TraitObligationStackList<'o, 'tcx>, obligation: PredicateObligation<'tcx>, ) -> Result<EvaluationResult, OverflowError> { + debug_assert!(!self.infcx.next_trait_solver()); // `previous_stack` stores a `TraitObligation`, while `obligation` is // a `PredicateObligation`. These are distinct types, so we can't // use any `Option` combinator method that would force them to be @@ -892,7 +873,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); use rustc_hir::def::DefKind; - use ty::ConstKind::Unevaluated; + use ty::Unevaluated; match (c1.kind(), c2.kind()) { (Unevaluated(a), Unevaluated(b)) if a.def == b.def && tcx.def_kind(a.def) == DefKind::AssocConst => @@ -967,9 +948,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } } - ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => { - bug!("TypeWellFormedFromEnv is only used for chalk") - } ty::PredicateKind::AliasRelate(..) => { bug!("AliasRelate is only used for new solver") } @@ -1177,6 +1155,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, stack: &TraitObligationStack<'o, 'tcx>, ) -> Result<EvaluationResult, OverflowError> { + debug_assert!(!self.infcx.next_trait_solver()); // In intercrate mode, whenever any of the generics are unbound, // there can always be an impl. Even if there are no impls in // this crate, perhaps the type would be unified with @@ -2292,8 +2271,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { fn constituent_types_for_ty( &self, t: ty::Binder<'tcx, Ty<'tcx>>, - ) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> { - match *t.skip_binder().kind() { + ) -> Result<ty::Binder<'tcx, Vec<Ty<'tcx>>>, SelectionError<'tcx>> { + Ok(match *t.skip_binder().kind() { ty::Uint(_) | ty::Int(_) | ty::Bool @@ -2306,7 +2285,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | ty::Char => ty::Binder::dummy(Vec::new()), // Treat this like `struct str([u8]);` - ty::Str => ty::Binder::dummy(vec![self.tcx().mk_slice(self.tcx().types.u8)]), + ty::Str => ty::Binder::dummy(vec![Ty::new_slice(self.tcx(), self.tcx().types.u8)]), ty::Placeholder(..) | ty::Dynamic(..) @@ -2357,12 +2336,16 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { + let ty = self.tcx().type_of(def_id); + if ty.skip_binder().references_error() { + return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id)); + } // We can resolve the `impl Trait` to its concrete type, // which enforces a DAG between the functions requiring // the auto trait bounds in question. - t.rebind(vec![self.tcx().type_of(def_id).subst(self.tcx(), substs)]) + t.rebind(vec![ty.subst(self.tcx(), substs)]) } - } + }) } fn collect_predicates_for_types( @@ -2452,7 +2435,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ), ); let value = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id); - let err = self.tcx().ty_error(guar); + let err = Ty::new_error(self.tcx(), guar); let value = value.fold_with(&mut BottomUpFolder { tcx: self.tcx(), ty_op: |_| err, diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index b6c64c0196a..302b6cacf2c 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -265,7 +265,7 @@ pub fn closure_trait_ref_and_return_type<'tcx>( assert!(!self_ty.has_escaping_bound_vars()); let arguments_tuple = match tuple_arguments { TupleArgumentsFlag::No => sig.skip_binder().inputs()[0], - TupleArgumentsFlag::Yes => tcx.mk_tup(sig.skip_binder().inputs()), + TupleArgumentsFlag::Yes => Ty::new_tup(tcx, sig.skip_binder().inputs()), }; let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, arguments_tuple]); sig.map_bound(|sig| (trait_ref, sig.output())) diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 8bb4288f80d..d81722ce22a 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -184,8 +184,7 @@ pub fn predicate_obligations<'tcx>( | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous - | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => { + | ty::PredicateKind::AliasRelate(..) => { bug!("We should only wf check where clauses, unexpected predicate: {predicate:?}") } } @@ -303,6 +302,16 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } fn normalize(self, infcx: &InferCtxt<'tcx>) -> Vec<traits::PredicateObligation<'tcx>> { + // Do not normalize `wf` obligations with the new solver. + // + // The current deep normalization routine with the new solver does not + // handle ambiguity and the new solver correctly deals with unnnormalized goals. + // If the user relies on normalized types, e.g. for `fn implied_outlives_bounds`, + // it is their responsibility to normalize while avoiding ambiguity. + if infcx.next_trait_solver() { + return self.out; + } + let cause = self.cause(traits::WellFormed(None)); let param_env = self.param_env; let mut obligations = Vec::with_capacity(self.out.len()); @@ -943,7 +952,7 @@ pub fn object_region_bounds<'tcx>( // Since we don't actually *know* the self type for an object, // this "open(err)" serves as a kind of dummy standin -- basically // a placeholder type. - let open_ty = tcx.mk_fresh_ty(0); + let open_ty = Ty::new_fresh(tcx, 0); let predicates = existential_predicates.iter().filter_map(|predicate| { if let ty::ExistentialPredicate::Projection(_) = predicate.skip_binder() { @@ -1005,8 +1014,7 @@ pub(crate) fn required_region_bounds<'tcx>( | ty::ClauseKind::Projection(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) - | ty::ClauseKind::TypeWellFormedFromEnv(_) => None, + | ty::ClauseKind::ConstEvaluatable(_) => None, } }) .collect() diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml index 189f72d478e..37e00c0e4bc 100644 --- a/compiler/rustc_traits/Cargo.toml +++ b/compiler/rustc_traits/Cargo.toml @@ -11,9 +11,6 @@ rustc_hir = { path = "../rustc_hir" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -chalk-ir = "0.92.0" -chalk-engine = "0.92.0" -chalk-solve = "0.92.0" smallvec = { version = "1.8.1", 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 deleted file mode 100644 index 0435cd63e80..00000000000 --- a/compiler/rustc_traits/src/chalk/db.rs +++ /dev/null @@ -1,796 +0,0 @@ -//! Provides the `RustIrDatabase` implementation for `chalk-solve` -//! -//! The purpose of the `chalk_solve::RustIrDatabase` is to get data about -//! specific types, such as bounds, where clauses, or fields. This file contains -//! the minimal logic to assemble the types for `chalk-solve` by calling out to -//! either the `TyCtxt` (for information about types) or -//! `crate::chalk::lowering` (to lower rustc types into Chalk types). - -use rustc_middle::traits::ChalkRustInterner as RustInterner; -use rustc_middle::ty::{self, AssocKind, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable}; -use rustc_middle::ty::{InternalSubsts, SubstsRef}; -use rustc_target::abi::{Integer, IntegerType}; - -use rustc_ast::ast; - -use rustc_hir::def_id::DefId; - -use rustc_span::symbol::sym; - -use std::fmt; -use std::sync::Arc; - -use crate::chalk::lowering::LowerInto; - -pub struct RustIrDatabase<'tcx> { - pub(crate) interner: RustInterner<'tcx>, -} - -impl fmt::Debug for RustIrDatabase<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "RustIrDatabase") - } -} - -impl<'tcx> RustIrDatabase<'tcx> { - fn where_clauses_for( - &self, - def_id: DefId, - bound_vars: SubstsRef<'tcx>, - ) -> Vec<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>> { - self.interner - .tcx - .predicates_defined_on(def_id) - .instantiate_own(self.interner.tcx, bound_vars) - .filter_map(|(wc, _)| LowerInto::lower_into(wc.as_predicate(), self.interner)) - .collect() - } - - fn bounds_for<T>(&self, def_id: DefId, bound_vars: SubstsRef<'tcx>) -> Vec<T> - where - ty::Predicate<'tcx>: LowerInto<'tcx, std::option::Option<T>>, - { - self.interner - .tcx - .explicit_item_bounds(def_id) - .subst_iter_copied(self.interner.tcx, &bound_vars) - .filter_map(|(bound, _)| { - LowerInto::<Option<_>>::lower_into(bound.as_predicate(), self.interner) - }) - .collect() - } -} - -impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'tcx> { - fn interner(&self) -> RustInterner<'tcx> { - self.interner - } - - fn associated_ty_data( - &self, - assoc_type_id: chalk_ir::AssocTypeId<RustInterner<'tcx>>, - ) -> Arc<chalk_solve::rust_ir::AssociatedTyDatum<RustInterner<'tcx>>> { - let def_id = assoc_type_id.0; - let assoc_item = self.interner.tcx.associated_item(def_id); - let Some(trait_def_id) = assoc_item.trait_container(self.interner.tcx) else { - unimplemented!("Not possible??"); - }; - match assoc_item.kind { - AssocKind::Type => {} - _ => unimplemented!("Not possible??"), - } - let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); - let binders = binders_for(self.interner, bound_vars); - - let where_clauses = self.where_clauses_for(def_id, bound_vars); - let bounds = self.bounds_for(def_id, bound_vars); - - Arc::new(chalk_solve::rust_ir::AssociatedTyDatum { - trait_id: chalk_ir::TraitId(trait_def_id), - id: assoc_type_id, - name: (), - binders: chalk_ir::Binders::new( - binders, - chalk_solve::rust_ir::AssociatedTyDatumBound { bounds, where_clauses }, - ), - }) - } - - fn trait_datum( - &self, - trait_id: chalk_ir::TraitId<RustInterner<'tcx>>, - ) -> Arc<chalk_solve::rust_ir::TraitDatum<RustInterner<'tcx>>> { - use chalk_solve::rust_ir::WellKnownTrait::*; - - let def_id = trait_id.0; - let trait_def = self.interner.tcx.trait_def(def_id); - - let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); - let binders = binders_for(self.interner, bound_vars); - - 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() - .filter(|i| i.kind == AssocKind::Type) - .map(|i| chalk_ir::AssocTypeId(i.def_id)) - .collect(); - - let lang_items = self.interner.tcx.lang_items(); - let well_known = if lang_items.sized_trait() == Some(def_id) { - Some(Sized) - } else if lang_items.copy_trait() == Some(def_id) { - Some(Copy) - } else if lang_items.clone_trait() == Some(def_id) { - Some(Clone) - } else if lang_items.drop_trait() == Some(def_id) { - Some(Drop) - } else if lang_items.fn_trait() == Some(def_id) { - Some(Fn) - } else if lang_items.fn_once_trait() == Some(def_id) { - Some(FnOnce) - } else if lang_items.fn_mut_trait() == Some(def_id) { - Some(FnMut) - } else if lang_items.unsize_trait() == Some(def_id) { - Some(Unsize) - } else if lang_items.unpin_trait() == Some(def_id) { - Some(Unpin) - } else if lang_items.coerce_unsized_trait() == Some(def_id) { - Some(CoerceUnsized) - } else if lang_items.dispatch_from_dyn_trait() == Some(def_id) { - Some(DispatchFromDyn) - } else if lang_items.tuple_trait() == Some(def_id) { - Some(Tuple) - } else { - None - }; - Arc::new(chalk_solve::rust_ir::TraitDatum { - id: trait_id, - binders: chalk_ir::Binders::new( - binders, - chalk_solve::rust_ir::TraitDatumBound { where_clauses }, - ), - flags: chalk_solve::rust_ir::TraitFlags { - auto: trait_def.has_auto_impl, - marker: trait_def.is_marker, - upstream: !def_id.is_local(), - fundamental: self.interner.tcx.has_attr(def_id, sym::fundamental), - non_enumerable: true, - coinductive: false, - }, - associated_ty_ids, - well_known, - }) - } - - fn adt_datum( - &self, - adt_id: chalk_ir::AdtId<RustInterner<'tcx>>, - ) -> Arc<chalk_solve::rust_ir::AdtDatum<RustInterner<'tcx>>> { - let adt_def = adt_id.0; - - let bound_vars = bound_vars_for_item(self.interner.tcx, adt_def.did()); - let binders = binders_for(self.interner, bound_vars); - - let where_clauses = self.where_clauses_for(adt_def.did(), bound_vars); - - let variants: Vec<_> = adt_def - .variants() - .iter() - .map(|variant| chalk_solve::rust_ir::AdtVariantDatum { - fields: variant - .fields - .iter() - .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 { 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(), - }, - 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<RustInterner<'tcx>>, - ) -> Arc<chalk_solve::rust_ir::AdtRepr<RustInterner<'tcx>>> { - let adt_def = adt_id.0; - let int = |i| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Int(i)).intern(self.interner); - let uint = |i| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Uint(i)).intern(self.interner); - Arc::new(chalk_solve::rust_ir::AdtRepr { - c: adt_def.repr().c(), - packed: adt_def.repr().packed(), - int: adt_def.repr().int.map(|i| match i { - IntegerType::Pointer(true) => int(chalk_ir::IntTy::Isize), - IntegerType::Pointer(false) => uint(chalk_ir::UintTy::Usize), - IntegerType::Fixed(i, true) => match i { - Integer::I8 => int(chalk_ir::IntTy::I8), - Integer::I16 => int(chalk_ir::IntTy::I16), - Integer::I32 => int(chalk_ir::IntTy::I32), - Integer::I64 => int(chalk_ir::IntTy::I64), - Integer::I128 => int(chalk_ir::IntTy::I128), - }, - IntegerType::Fixed(i, false) => match i { - Integer::I8 => uint(chalk_ir::UintTy::U8), - Integer::I16 => uint(chalk_ir::UintTy::U16), - Integer::I32 => uint(chalk_ir::UintTy::U32), - Integer::I64 => uint(chalk_ir::UintTy::U64), - Integer::I128 => uint(chalk_ir::UintTy::U128), - }, - }), - }) - } - - fn adt_size_align( - &self, - adt_id: chalk_ir::AdtId<RustInterner<'tcx>>, - ) -> Arc<chalk_solve::rust_ir::AdtSizeAlign> { - let tcx = self.interner.tcx; - let did = adt_id.0.did(); - - // Grab the ADT and the param we might need to calculate its layout - let param_env = tcx.param_env(did); - let adt_ty = tcx.type_of(did).subst_identity(); - - // The ADT is a 1-zst if it's a ZST and its alignment is 1. - // Mark the ADT as _not_ a 1-zst if there was a layout error. - let one_zst = if let Ok(layout) = tcx.layout_of(param_env.and(adt_ty)) { - layout.is_zst() && layout.align.abi.bytes() == 1 - } else { - false - }; - - Arc::new(chalk_solve::rust_ir::AdtSizeAlign::from_one_zst(one_zst)) - } - - fn fn_def_datum( - &self, - fn_def_id: chalk_ir::FnDefId<RustInterner<'tcx>>, - ) -> Arc<chalk_solve::rust_ir::FnDefDatum<RustInterner<'tcx>>> { - let def_id = fn_def_id.0; - let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); - let binders = binders_for(self.interner, bound_vars); - - let where_clauses = self.where_clauses_for(def_id, bound_vars); - - let sig = self.interner.tcx.fn_sig(def_id); - let (inputs_and_output, iobinders, _) = crate::chalk::lowering::collect_bound_vars( - self.interner, - self.interner.tcx, - sig.map_bound(|s| s.inputs_and_output()).subst(self.interner.tcx, bound_vars), - ); - - let argument_types = inputs_and_output[..inputs_and_output.len() - 1] - .iter() - .map(|t| sig.rebind(*t).subst(self.interner.tcx, &bound_vars).lower_into(self.interner)) - .collect(); - - let return_type = sig - .rebind(inputs_and_output[inputs_and_output.len() - 1]) - .subst(self.interner.tcx, &bound_vars) - .lower_into(self.interner); - - let bound = chalk_solve::rust_ir::FnDefDatumBound { - inputs_and_output: chalk_ir::Binders::new( - iobinders, - chalk_solve::rust_ir::FnDefInputsAndOutputDatum { argument_types, return_type }, - ), - where_clauses, - }; - Arc::new(chalk_solve::rust_ir::FnDefDatum { - id: fn_def_id, - sig: sig.skip_binder().lower_into(self.interner), - binders: chalk_ir::Binders::new(binders, bound), - }) - } - - fn impl_datum( - &self, - impl_id: chalk_ir::ImplId<RustInterner<'tcx>>, - ) -> Arc<chalk_solve::rust_ir::ImplDatum<RustInterner<'tcx>>> { - let def_id = impl_id.0; - let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); - let binders = binders_for(self.interner, 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 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), - where_clauses, - }; - - let associated_ty_value_ids: Vec<_> = self - .interner - .tcx - .associated_items(def_id) - .in_definition_order() - .filter(|i| i.kind == AssocKind::Type) - .map(|i| chalk_solve::rust_ir::AssociatedTyValueId(i.def_id)) - .collect(); - - Arc::new(chalk_solve::rust_ir::ImplDatum { - polarity: self.interner.tcx.impl_polarity(def_id).lower_into(self.interner), - binders: chalk_ir::Binders::new(binders, value), - impl_type: chalk_solve::rust_ir::ImplType::Local, - associated_ty_value_ids, - }) - } - - fn impls_for_trait( - &self, - trait_id: chalk_ir::TraitId<RustInterner<'tcx>>, - parameters: &[chalk_ir::GenericArg<RustInterner<'tcx>>], - _binders: &chalk_ir::CanonicalVarKinds<RustInterner<'tcx>>, - ) -> Vec<chalk_ir::ImplId<RustInterner<'tcx>>> { - let def_id = trait_id.0; - - // FIXME(chalk): use TraitDef::for_each_relevant_impl, but that will - // require us to be able to interconvert `Ty<'tcx>`, and we're - // not there yet. - - 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.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.map_bound(|t| t.self_ty()); - let self_ty = self_ty.subst(self.interner.tcx, bound_vars); - let lowered_ty = self_ty.lower_into(self.interner); - - parameters[0].assert_ty_ref(self.interner).could_match( - self.interner, - self.unification_database(), - &lowered_ty, - ) - }); - - let impls = matched_impls.map(chalk_ir::ImplId).collect(); - impls - } - - fn impl_provided_for( - &self, - auto_trait_id: chalk_ir::TraitId<RustInterner<'tcx>>, - chalk_ty: &chalk_ir::TyKind<RustInterner<'tcx>>, - ) -> bool { - use chalk_ir::Scalar::*; - use chalk_ir::TyKind::*; - - let trait_def_id = auto_trait_id.0; - let all_impls = self.interner.tcx.all_impls(trait_def_id); - for impl_def_id in all_impls { - let trait_ref = self.interner.tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity(); - let self_ty = trait_ref.self_ty(); - let provides = match (self_ty.kind(), chalk_ty) { - (&ty::Adt(impl_adt_def, ..), Adt(id, ..)) => impl_adt_def.did() == id.0.did(), - (_, AssociatedType(_ty_id, ..)) => { - // FIXME(chalk): See https://github.com/rust-lang/rust/pull/77152#discussion_r494484774 - false - } - (ty::Bool, Scalar(Bool)) => true, - (ty::Char, Scalar(Char)) => true, - (ty::Int(ty1), Scalar(Int(ty2))) => matches!( - (ty1, ty2), - (ty::IntTy::Isize, chalk_ir::IntTy::Isize) - | (ty::IntTy::I8, chalk_ir::IntTy::I8) - | (ty::IntTy::I16, chalk_ir::IntTy::I16) - | (ty::IntTy::I32, chalk_ir::IntTy::I32) - | (ty::IntTy::I64, chalk_ir::IntTy::I64) - | (ty::IntTy::I128, chalk_ir::IntTy::I128) - ), - (ty::Uint(ty1), Scalar(Uint(ty2))) => matches!( - (ty1, ty2), - (ty::UintTy::Usize, chalk_ir::UintTy::Usize) - | (ty::UintTy::U8, chalk_ir::UintTy::U8) - | (ty::UintTy::U16, chalk_ir::UintTy::U16) - | (ty::UintTy::U32, chalk_ir::UintTy::U32) - | (ty::UintTy::U64, chalk_ir::UintTy::U64) - | (ty::UintTy::U128, chalk_ir::UintTy::U128) - ), - (ty::Float(ty1), Scalar(Float(ty2))) => matches!( - (ty1, ty2), - (ty::FloatTy::F32, chalk_ir::FloatTy::F32) - | (ty::FloatTy::F64, chalk_ir::FloatTy::F64) - ), - (&ty::Tuple(substs), Tuple(len, _)) => substs.len() == *len, - (&ty::Array(..), Array(..)) => true, - (&ty::Slice(..), Slice(..)) => true, - (&ty::RawPtr(type_and_mut), Raw(mutability, _)) => { - match (type_and_mut.mutbl, mutability) { - (ast::Mutability::Mut, chalk_ir::Mutability::Mut) => true, - (ast::Mutability::Mut, chalk_ir::Mutability::Not) => false, - (ast::Mutability::Not, chalk_ir::Mutability::Mut) => false, - (ast::Mutability::Not, chalk_ir::Mutability::Not) => true, - } - } - (&ty::Ref(.., mutability1), Ref(mutability2, ..)) => { - match (mutability1, mutability2) { - (ast::Mutability::Mut, chalk_ir::Mutability::Mut) => true, - (ast::Mutability::Mut, chalk_ir::Mutability::Not) => false, - (ast::Mutability::Not, chalk_ir::Mutability::Mut) => false, - (ast::Mutability::Not, chalk_ir::Mutability::Not) => true, - } - } - ( - &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), - OpaqueType(opaque_ty_id, ..), - ) => def_id == opaque_ty_id.0, - (&ty::FnDef(def_id, ..), FnDef(fn_def_id, ..)) => def_id == fn_def_id.0, - (&ty::Str, Str) => true, - (&ty::Never, Never) => true, - (&ty::Closure(def_id, ..), Closure(closure_id, _)) => def_id == closure_id.0, - (&ty::Foreign(def_id), Foreign(foreign_def_id)) => def_id == foreign_def_id.0, - (&ty::Error(..), Error) => false, - _ => false, - }; - if provides { - return true; - } - } - false - } - - fn associated_ty_value( - &self, - associated_ty_id: chalk_solve::rust_ir::AssociatedTyValueId<RustInterner<'tcx>>, - ) -> Arc<chalk_solve::rust_ir::AssociatedTyValue<RustInterner<'tcx>>> { - let def_id = associated_ty_id.0; - let assoc_item = self.interner.tcx.associated_item(def_id); - let impl_id = assoc_item.container_id(self.interner.tcx); - match assoc_item.kind { - AssocKind::Type => {} - _ => unimplemented!("Not possible??"), - } - - let trait_item_id = assoc_item.trait_item_def_id.expect("assoc_ty with no trait version"); - let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); - let binders = binders_for(self.interner, bound_vars); - let ty = self - .interner - .tcx - .type_of(def_id) - .subst(self.interner.tcx, bound_vars) - .lower_into(self.interner); - - Arc::new(chalk_solve::rust_ir::AssociatedTyValue { - impl_id: chalk_ir::ImplId(impl_id), - associated_ty_id: chalk_ir::AssocTypeId(trait_item_id), - value: chalk_ir::Binders::new( - binders, - chalk_solve::rust_ir::AssociatedTyValueBound { ty }, - ), - }) - } - - fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<RustInterner<'tcx>>> { - vec![] - } - - fn local_impls_to_coherence_check( - &self, - _trait_id: chalk_ir::TraitId<RustInterner<'tcx>>, - ) -> Vec<chalk_ir::ImplId<RustInterner<'tcx>>> { - unimplemented!() - } - - fn opaque_ty_data( - &self, - opaque_ty_id: chalk_ir::OpaqueTyId<RustInterner<'tcx>>, - ) -> Arc<chalk_solve::rust_ir::OpaqueTyDatum<RustInterner<'tcx>>> { - let bound_vars = ty::fold::shift_vars( - self.interner.tcx, - bound_vars_for_item(self.interner.tcx, opaque_ty_id.0), - 1, - ); - let where_clauses = self.where_clauses_for(opaque_ty_id.0, bound_vars); - - let identity_substs = InternalSubsts::identity_for_item(self.interner.tcx, opaque_ty_id.0); - - let explicit_item_bounds = self.interner.tcx.explicit_item_bounds(opaque_ty_id.0); - let bounds = - explicit_item_bounds - .subst_iter_copied(self.interner.tcx, &bound_vars) - .map(|(bound, _)| { - bound.fold_with(&mut ReplaceOpaqueTyFolder { - tcx: self.interner.tcx, - opaque_ty_id, - identity_substs, - binder_index: ty::INNERMOST, - }) - }) - .filter_map(|bound| { - LowerInto::< - Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>> - >::lower_into(bound.as_predicate(), self.interner) - }) - .collect(); - - // Binder for the bound variable representing the concrete impl Trait type. - let existential_binder = chalk_ir::VariableKinds::from1( - self.interner, - chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), - ); - - let value = chalk_solve::rust_ir::OpaqueTyDatumBound { - bounds: chalk_ir::Binders::new(existential_binder.clone(), bounds), - where_clauses: chalk_ir::Binders::new(existential_binder, where_clauses), - }; - - let binders = binders_for(self.interner, bound_vars); - Arc::new(chalk_solve::rust_ir::OpaqueTyDatum { - opaque_ty_id, - bound: chalk_ir::Binders::new(binders, value), - }) - } - - fn program_clauses_for_env( - &self, - environment: &chalk_ir::Environment<RustInterner<'tcx>>, - ) -> chalk_ir::ProgramClauses<RustInterner<'tcx>> { - chalk_solve::program_clauses_for_env(self, environment) - } - - fn well_known_trait_id( - &self, - well_known_trait: chalk_solve::rust_ir::WellKnownTrait, - ) -> Option<chalk_ir::TraitId<RustInterner<'tcx>>> { - use chalk_solve::rust_ir::WellKnownTrait::*; - let lang_items = self.interner.tcx.lang_items(); - let def_id = match well_known_trait { - Sized => lang_items.sized_trait(), - Copy => lang_items.copy_trait(), - Clone => lang_items.clone_trait(), - Drop => lang_items.drop_trait(), - Fn => lang_items.fn_trait(), - FnMut => lang_items.fn_mut_trait(), - FnOnce => lang_items.fn_once_trait(), - Generator => lang_items.gen_trait(), - Unsize => lang_items.unsize_trait(), - Unpin => lang_items.unpin_trait(), - CoerceUnsized => lang_items.coerce_unsized_trait(), - DiscriminantKind => lang_items.discriminant_kind_trait(), - DispatchFromDyn => lang_items.dispatch_from_dyn_trait(), - Tuple => lang_items.tuple_trait(), - Pointee => lang_items.pointee_trait(), - FnPtr => lang_items.fn_ptr_trait(), - }; - def_id.map(chalk_ir::TraitId) - } - - fn is_object_safe(&self, trait_id: chalk_ir::TraitId<RustInterner<'tcx>>) -> bool { - self.interner.tcx.check_is_object_safe(trait_id.0) - } - - fn hidden_opaque_type( - &self, - _id: chalk_ir::OpaqueTyId<RustInterner<'tcx>>, - ) -> chalk_ir::Ty<RustInterner<'tcx>> { - // FIXME(chalk): actually get hidden ty - self.interner.tcx.types.unit.lower_into(self.interner) - } - - fn closure_kind( - &self, - _closure_id: chalk_ir::ClosureId<RustInterner<'tcx>>, - substs: &chalk_ir::Substitution<RustInterner<'tcx>>, - ) -> chalk_solve::rust_ir::ClosureKind { - let kind = &substs.as_slice(self.interner)[substs.len(self.interner) - 3]; - match kind.assert_ty_ref(self.interner).kind(self.interner) { - chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Int(int_ty)) => match int_ty { - chalk_ir::IntTy::I8 => chalk_solve::rust_ir::ClosureKind::Fn, - chalk_ir::IntTy::I16 => chalk_solve::rust_ir::ClosureKind::FnMut, - chalk_ir::IntTy::I32 => chalk_solve::rust_ir::ClosureKind::FnOnce, - _ => bug!("bad closure kind"), - }, - _ => bug!("bad closure kind"), - } - } - - fn closure_inputs_and_output( - &self, - _closure_id: chalk_ir::ClosureId<RustInterner<'tcx>>, - substs: &chalk_ir::Substitution<RustInterner<'tcx>>, - ) -> chalk_ir::Binders<chalk_solve::rust_ir::FnDefInputsAndOutputDatum<RustInterner<'tcx>>> - { - let sig = &substs.as_slice(self.interner)[substs.len(self.interner) - 2]; - match sig.assert_ty_ref(self.interner).kind(self.interner) { - chalk_ir::TyKind::Function(f) => { - let substitution = f.substitution.0.as_slice(self.interner); - let return_type = substitution.last().unwrap().assert_ty_ref(self.interner).clone(); - // Closure arguments are tupled - let argument_tuple = substitution[0].assert_ty_ref(self.interner); - let argument_types = match argument_tuple.kind(self.interner) { - chalk_ir::TyKind::Tuple(_len, substitution) => substitution - .iter(self.interner) - .map(|arg| arg.assert_ty_ref(self.interner)) - .cloned() - .collect(), - _ => bug!("Expecting closure FnSig args to be tupled."), - }; - - chalk_ir::Binders::new( - chalk_ir::VariableKinds::from_iter( - self.interner, - (0..f.num_binders).map(|_| chalk_ir::VariableKind::Lifetime), - ), - chalk_solve::rust_ir::FnDefInputsAndOutputDatum { argument_types, return_type }, - ) - } - _ => panic!("Invalid sig."), - } - } - - fn closure_upvars( - &self, - _closure_id: chalk_ir::ClosureId<RustInterner<'tcx>>, - substs: &chalk_ir::Substitution<RustInterner<'tcx>>, - ) -> chalk_ir::Binders<chalk_ir::Ty<RustInterner<'tcx>>> { - let inputs_and_output = self.closure_inputs_and_output(_closure_id, substs); - let tuple = substs.as_slice(self.interner).last().unwrap().assert_ty_ref(self.interner); - inputs_and_output.map_ref(|_| tuple.clone()) - } - - fn closure_fn_substitution( - &self, - _closure_id: chalk_ir::ClosureId<RustInterner<'tcx>>, - substs: &chalk_ir::Substitution<RustInterner<'tcx>>, - ) -> chalk_ir::Substitution<RustInterner<'tcx>> { - let substitution = &substs.as_slice(self.interner)[0..substs.len(self.interner) - 3]; - chalk_ir::Substitution::from_iter(self.interner, substitution) - } - - fn generator_datum( - &self, - _generator_id: chalk_ir::GeneratorId<RustInterner<'tcx>>, - ) -> Arc<chalk_solve::rust_ir::GeneratorDatum<RustInterner<'tcx>>> { - unimplemented!() - } - - fn generator_witness_datum( - &self, - _generator_id: chalk_ir::GeneratorId<RustInterner<'tcx>>, - ) -> Arc<chalk_solve::rust_ir::GeneratorWitnessDatum<RustInterner<'tcx>>> { - unimplemented!() - } - - fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase<RustInterner<'tcx>> { - self - } - - fn discriminant_type( - &self, - _: chalk_ir::Ty<RustInterner<'tcx>>, - ) -> chalk_ir::Ty<RustInterner<'tcx>> { - unimplemented!() - } -} - -impl<'tcx> chalk_ir::UnificationDatabase<RustInterner<'tcx>> for RustIrDatabase<'tcx> { - fn fn_def_variance( - &self, - def_id: chalk_ir::FnDefId<RustInterner<'tcx>>, - ) -> chalk_ir::Variances<RustInterner<'tcx>> { - let variances = self.interner.tcx.variances_of(def_id.0); - chalk_ir::Variances::from_iter( - self.interner, - variances.iter().map(|v| v.lower_into(self.interner)), - ) - } - - fn adt_variance( - &self, - adt_id: chalk_ir::AdtId<RustInterner<'tcx>>, - ) -> chalk_ir::Variances<RustInterner<'tcx>> { - let variances = self.interner.tcx.variances_of(adt_id.0.did()); - chalk_ir::Variances::from_iter( - self.interner, - variances.iter().map(|v| v.lower_into(self.interner)), - ) - } -} - -/// Creates an `InternalSubsts` that maps each generic parameter to a higher-ranked -/// var bound at index `0`. For types, we use a `BoundVar` index equal to -/// the type parameter index. For regions, we use the `BoundRegionKind::BrNamed` -/// variant (which has a `DefId`). -fn bound_vars_for_item(tcx: TyCtxt<'_>, def_id: DefId) -> SubstsRef<'_> { - InternalSubsts::for_item(tcx, def_id, |param, substs| match param.kind { - ty::GenericParamDefKind::Type { .. } => tcx - .mk_bound( - ty::INNERMOST, - ty::BoundTy { - var: ty::BoundVar::from(param.index), - kind: ty::BoundTyKind::Param(param.def_id, param.name), - }, - ) - .into(), - - ty::GenericParamDefKind::Lifetime => { - let br = ty::BoundRegion { - var: ty::BoundVar::from_usize(substs.len()), - kind: ty::BrAnon(None), - }; - ty::Region::new_late_bound(tcx, ty::INNERMOST, br).into() - } - - ty::GenericParamDefKind::Const { .. } => tcx - .mk_const( - ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from(param.index)), - tcx.type_of(param.def_id).subst_identity(), - ) - .into(), - }) -} - -fn binders_for<'tcx>( - interner: RustInterner<'tcx>, - bound_vars: SubstsRef<'tcx>, -) -> chalk_ir::VariableKinds<RustInterner<'tcx>> { - chalk_ir::VariableKinds::from_iter( - interner, - bound_vars.iter().map(|arg| match arg.unpack() { - ty::subst::GenericArgKind::Lifetime(_re) => chalk_ir::VariableKind::Lifetime, - ty::subst::GenericArgKind::Type(_ty) => { - chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General) - } - ty::subst::GenericArgKind::Const(c) => { - chalk_ir::VariableKind::Const(c.ty().lower_into(interner)) - } - }), - ) -} - -struct ReplaceOpaqueTyFolder<'tcx> { - tcx: TyCtxt<'tcx>, - opaque_ty_id: chalk_ir::OpaqueTyId<RustInterner<'tcx>>, - identity_substs: SubstsRef<'tcx>, - binder_index: ty::DebruijnIndex, -} - -impl<'tcx> ty::TypeFolder<TyCtxt<'tcx>> for ReplaceOpaqueTyFolder<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>( - &mut self, - t: ty::Binder<'tcx, T>, - ) -> ty::Binder<'tcx, T> { - self.binder_index.shift_in(1); - let t = t.super_fold_with(self); - self.binder_index.shift_out(1); - t - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) = *ty.kind() { - if def_id == self.opaque_ty_id.0 && substs == self.identity_substs { - return self - .tcx - .mk_bound(self.binder_index, ty::BoundTy::from(ty::BoundVar::from_u32(0))); - } - } - ty - } -} diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs deleted file mode 100644 index b7db56d3db8..00000000000 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ /dev/null @@ -1,1234 +0,0 @@ -//! Contains the logic to lower rustc types into Chalk types -//! -//! In many cases there is a 1:1 relationship between a rustc type and a Chalk type. -//! For example, a `SubstsRef` maps almost directly to a `Substitution`. In some -//! other cases, such as `Param`s, there is no Chalk type, so we have to handle -//! accordingly. -//! -//! ## `Ty` lowering -//! Much of the `Ty` lowering is 1:1 with Chalk. (Or will be eventually). A -//! helpful table for what types lower to what can be found in the -//! [Chalk book](https://rust-lang.github.io/chalk/book/types/rust_types.html). -//! The most notable difference lies with `Param`s. To convert from rustc to -//! Chalk, we eagerly and deeply convert `Param`s to placeholders (in goals) or -//! bound variables (for clause generation through functions in `db`). -//! -//! ## `Region` lowering -//! Regions are handled in rustc and Chalk is quite differently. In rustc, there -//! is a difference between "early bound" and "late bound" regions, where only -//! the late bound regions have a `DebruijnIndex`. Moreover, in Chalk all -//! regions (Lifetimes) have an associated index. In rustc, only `BrAnon`s have -//! an index, whereas `BrNamed` don't. In order to lower regions to Chalk, we -//! convert all regions into `BrAnon` late-bound regions. -//! -//! ## `Const` lowering -//! Chalk doesn't handle consts currently, so consts are currently lowered to -//! an empty tuple. -//! -//! ## Bound variable collection -//! Another difference between rustc and Chalk lies in the handling of binders. -//! Chalk requires that we store the bound parameter kinds, whereas rustc does -//! not. To lower anything wrapped in a `Binder`, we first deeply find any bound -//! variables from the current `Binder`. - -use rustc_ast::ast; -use rustc_middle::traits::{ChalkEnvironmentAndGoal, ChalkRustInterner as RustInterner}; -use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; -use rustc_middle::ty::{ - self, Binder, Region, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, - TypeSuperVisitable, TypeVisitable, TypeVisitor, -}; -use rustc_span::def_id::DefId; - -use chalk_ir::{FnSig, ForeignDefId}; -use rustc_hir::Unsafety; -use std::collections::btree_map::{BTreeMap, Entry}; -use std::ops::ControlFlow; - -/// Essentially an `Into` with a `&RustInterner` parameter -pub(crate) trait LowerInto<'tcx, T> { - /// Lower a rustc construct (e.g., `ty::TraitPredicate`) to a chalk type, consuming `self`. - fn lower_into(self, interner: RustInterner<'tcx>) -> T; -} - -impl<'tcx> LowerInto<'tcx, chalk_ir::Substitution<RustInterner<'tcx>>> for SubstsRef<'tcx> { - fn lower_into( - self, - interner: RustInterner<'tcx>, - ) -> chalk_ir::Substitution<RustInterner<'tcx>> { - chalk_ir::Substitution::from_iter(interner, self.iter().map(|s| s.lower_into(interner))) - } -} - -impl<'tcx> LowerInto<'tcx, chalk_ir::Substitution<RustInterner<'tcx>>> - for &'tcx ty::List<Ty<'tcx>> -{ - fn lower_into( - self, - interner: RustInterner<'tcx>, - ) -> chalk_ir::Substitution<RustInterner<'tcx>> { - chalk_ir::Substitution::from_iter( - interner, - self.iter().map(|ty| GenericArg::from(ty).lower_into(interner)), - ) - } -} - -impl<'tcx> LowerInto<'tcx, SubstsRef<'tcx>> for &chalk_ir::Substitution<RustInterner<'tcx>> { - fn lower_into(self, interner: RustInterner<'tcx>) -> SubstsRef<'tcx> { - interner - .tcx - .mk_substs_from_iter(self.iter(interner).map(|subst| subst.lower_into(interner))) - } -} - -impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'tcx>>>> - for ChalkEnvironmentAndGoal<'tcx> -{ - fn lower_into( - self, - interner: RustInterner<'tcx>, - ) -> chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'tcx>>> { - let clauses = self.environment.into_iter().map(|predicate| { - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, predicate.kind()); - let consequence = match predicate { - ty::ClauseKind::TypeWellFormedFromEnv(ty) => { - chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner))) - } - ty::ClauseKind::Trait(predicate) => chalk_ir::DomainGoal::FromEnv( - chalk_ir::FromEnv::Trait(predicate.trait_ref.lower_into(interner)), - ), - ty::ClauseKind::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::ClauseKind::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::ClauseKind::Projection(predicate) => chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)), - ), - ty::ClauseKind::WellFormed(arg) => match arg.unpack() { - ty::GenericArgKind::Type(ty) => chalk_ir::DomainGoal::WellFormed( - chalk_ir::WellFormed::Ty(ty.lower_into(interner)), - ), - // FIXME(chalk): we need to change `WellFormed` in Chalk to take a `GenericArg` - _ => chalk_ir::DomainGoal::WellFormed(chalk_ir::WellFormed::Ty( - interner.tcx.types.unit.lower_into(interner), - )), - }, - ty::ClauseKind::ConstArgHasType(..) | ty::ClauseKind::ConstEvaluatable(_) => { - 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) - }); - - let goal: chalk_ir::GoalData<RustInterner<'tcx>> = self.goal.lower_into(interner); - chalk_ir::InEnvironment { - environment: chalk_ir::Environment { - clauses: chalk_ir::ProgramClauses::from_iter(interner, clauses), - }, - goal: goal.intern(interner), - } - } -} - -impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predicate<'tcx> { - fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::GoalData<RustInterner<'tcx>> { - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, self.kind()); - - let value = match predicate { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner)), - )) - } - ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => { - 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), - }), - )) - } - ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => { - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { - ty: predicate.0.lower_into(interner), - lifetime: predicate.1.lower_into(interner), - }), - )) - } - ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => { - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)), - )) - } - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => match arg.unpack() { - GenericArgKind::Type(ty) => match ty.kind() { - // FIXME(chalk): In Chalk, a placeholder is WellFormed if it - // `FromEnv`. However, when we "lower" Params, we don't update - // the environment. - 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::empty(interner)) - } - GenericArgKind::Lifetime(lt) => bug!("unexpected well formed predicate: {:?}", lt), - }, - - ty::PredicateKind::ObjectSafe(t) => chalk_ir::GoalData::DomainGoal( - chalk_ir::DomainGoal::ObjectSafe(chalk_ir::TraitId(t)), - ), - - ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ }) => { - chalk_ir::GoalData::SubtypeGoal(chalk_ir::SubtypeGoal { - a: a.lower_into(interner), - b: b.lower_into(interner), - }) - } - - // FIXME(chalk): other predicates - // - // We can defer this, but ultimately we'll want to express - // some of these in terms of chalk operations. - ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) - | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) - | ty::PredicateKind::Ambiguous - | ty::PredicateKind::ConstEquate(..) => { - chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) - } - ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(ty)) => { - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::FromEnv( - chalk_ir::FromEnv::Ty(ty.lower_into(interner)), - )) - } - }; - - chalk_ir::GoalData::Quantified( - chalk_ir::QuantifierKind::ForAll, - chalk_ir::Binders::new(binders, value.intern(interner)), - ) - } -} - -impl<'tcx> LowerInto<'tcx, chalk_ir::TraitRef<RustInterner<'tcx>>> - for rustc_middle::ty::TraitRef<'tcx> -{ - fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::TraitRef<RustInterner<'tcx>> { - chalk_ir::TraitRef { - trait_id: chalk_ir::TraitId(self.def_id), - substitution: self.substs.lower_into(interner), - } - } -} - -impl<'tcx> LowerInto<'tcx, chalk_ir::AliasEq<RustInterner<'tcx>>> - for rustc_middle::ty::ProjectionPredicate<'tcx> -{ - fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::AliasEq<RustInterner<'tcx>> { - // FIXME(associated_const_equality): teach chalk about terms for alias eq. - chalk_ir::AliasEq { - ty: self.term.ty().unwrap().lower_into(interner), - alias: chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { - associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.def_id), - substitution: self.projection_ty.substs.lower_into(interner), - }), - } - } -} - -/* -// FIXME(...): Where do I add this to Chalk? I can't find it in the rustc repo anywhere. -impl<'tcx> LowerInto<'tcx, chalk_ir::Term<RustInterner<'tcx>>> for rustc_middle::ty::Term<'tcx> { - fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Term<RustInterner<'tcx>> { - match self { - ty::Term::Ty(ty) => ty.lower_into(interner).into(), - ty::Term::Const(c) => c.lower_into(interner).into(), - } - } -} -*/ - -impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> { - fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Ty<RustInterner<'tcx>> { - let int = |i| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Int(i)); - let uint = |i| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Uint(i)); - let float = |f| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Float(f)); - - match *self.kind() { - ty::Bool => chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Bool), - ty::Char => chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Char), - ty::Int(ty) => match ty { - ty::IntTy::Isize => int(chalk_ir::IntTy::Isize), - ty::IntTy::I8 => int(chalk_ir::IntTy::I8), - ty::IntTy::I16 => int(chalk_ir::IntTy::I16), - ty::IntTy::I32 => int(chalk_ir::IntTy::I32), - ty::IntTy::I64 => int(chalk_ir::IntTy::I64), - ty::IntTy::I128 => int(chalk_ir::IntTy::I128), - }, - ty::Uint(ty) => match ty { - ty::UintTy::Usize => uint(chalk_ir::UintTy::Usize), - ty::UintTy::U8 => uint(chalk_ir::UintTy::U8), - ty::UintTy::U16 => uint(chalk_ir::UintTy::U16), - ty::UintTy::U32 => uint(chalk_ir::UintTy::U32), - ty::UintTy::U64 => uint(chalk_ir::UintTy::U64), - ty::UintTy::U128 => uint(chalk_ir::UintTy::U128), - }, - ty::Float(ty) => match ty { - ty::FloatTy::F32 => float(chalk_ir::FloatTy::F32), - ty::FloatTy::F64 => float(chalk_ir::FloatTy::F64), - }, - ty::Adt(def, substs) => { - chalk_ir::TyKind::Adt(chalk_ir::AdtId(def), substs.lower_into(interner)) - } - ty::Foreign(def_id) => chalk_ir::TyKind::Foreign(ForeignDefId(def_id)), - ty::Str => chalk_ir::TyKind::Str, - ty::Array(ty, len) => { - chalk_ir::TyKind::Array(ty.lower_into(interner), len.lower_into(interner)) - } - ty::Slice(ty) => chalk_ir::TyKind::Slice(ty.lower_into(interner)), - - ty::RawPtr(ptr) => { - chalk_ir::TyKind::Raw(ptr.mutbl.lower_into(interner), ptr.ty.lower_into(interner)) - } - ty::Ref(region, ty, mutability) => chalk_ir::TyKind::Ref( - mutability.lower_into(interner), - region.lower_into(interner), - ty.lower_into(interner), - ), - ty::FnDef(def_id, substs) => { - chalk_ir::TyKind::FnDef(chalk_ir::FnDefId(def_id), substs.lower_into(interner)) - } - ty::FnPtr(sig) => { - let (inputs_and_outputs, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, sig.inputs_and_output()); - chalk_ir::TyKind::Function(chalk_ir::FnPointer { - num_binders: binders.len(interner), - sig: sig.lower_into(interner), - substitution: chalk_ir::FnSubst(chalk_ir::Substitution::from_iter( - interner, - inputs_and_outputs.iter().map(|ty| { - chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner) - }), - )), - }) - } - // FIXME(dyn-star): handle the dynamic kind (dyn or dyn*) - ty::Dynamic(predicates, region, _kind) => chalk_ir::TyKind::Dyn(chalk_ir::DynTy { - bounds: predicates.lower_into(interner), - lifetime: region.lower_into(interner), - }), - ty::Closure(def_id, substs) => { - chalk_ir::TyKind::Closure(chalk_ir::ClosureId(def_id), substs.lower_into(interner)) - } - ty::Generator(def_id, substs, _) => chalk_ir::TyKind::Generator( - chalk_ir::GeneratorId(def_id), - substs.lower_into(interner), - ), - ty::GeneratorWitness(_) => unimplemented!(), - ty::GeneratorWitnessMIR(..) => unimplemented!(), - ty::Never => chalk_ir::TyKind::Never, - ty::Tuple(types) => chalk_ir::TyKind::Tuple(types.len(), types.lower_into(interner)), - ty::Alias(ty::Projection, ty::AliasTy { def_id, substs, .. }) => { - chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { - associated_ty_id: chalk_ir::AssocTypeId(def_id), - substitution: substs.lower_into(interner), - })) - } - ty::Alias(ty::Weak, ty::AliasTy { .. }) => unimplemented!(), - ty::Alias(ty::Inherent, _) => unimplemented!(), - ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { - chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy { - opaque_ty_id: chalk_ir::OpaqueTyId(def_id), - substitution: substs.lower_into(interner), - })) - } - // This should have been done eagerly prior to this, and all Params - // should have been substituted to placeholders - ty::Param(_) => panic!("Lowering Param when not expected."), - ty::Bound(db, bound) => chalk_ir::TyKind::BoundVar(chalk_ir::BoundVar::new( - chalk_ir::DebruijnIndex::new(db.as_u32()), - bound.var.index(), - )), - ty::Placeholder(_placeholder) => { - chalk_ir::TyKind::Placeholder(chalk_ir::PlaceholderIndex { - ui: chalk_ir::UniverseIndex { counter: _placeholder.universe.as_usize() }, - idx: _placeholder.bound.var.as_usize(), - }) - } - ty::Infer(_infer) => unimplemented!(), - ty::Error(_) => chalk_ir::TyKind::Error, - } - .intern(interner) - } -} - -impl<'tcx> LowerInto<'tcx, Ty<'tcx>> for &chalk_ir::Ty<RustInterner<'tcx>> { - fn lower_into(self, interner: RustInterner<'tcx>) -> Ty<'tcx> { - use chalk_ir::TyKind; - - let kind = match self.kind(interner) { - TyKind::Adt(struct_id, substitution) => { - ty::Adt(struct_id.0, substitution.lower_into(interner)) - } - TyKind::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(ty::IntTy::Isize), - chalk_ir::IntTy::I8 => ty::Int(ty::IntTy::I8), - chalk_ir::IntTy::I16 => ty::Int(ty::IntTy::I16), - chalk_ir::IntTy::I32 => ty::Int(ty::IntTy::I32), - chalk_ir::IntTy::I64 => ty::Int(ty::IntTy::I64), - chalk_ir::IntTy::I128 => ty::Int(ty::IntTy::I128), - }, - chalk_ir::Scalar::Uint(int_ty) => match int_ty { - chalk_ir::UintTy::Usize => ty::Uint(ty::UintTy::Usize), - chalk_ir::UintTy::U8 => ty::Uint(ty::UintTy::U8), - chalk_ir::UintTy::U16 => ty::Uint(ty::UintTy::U16), - chalk_ir::UintTy::U32 => ty::Uint(ty::UintTy::U32), - chalk_ir::UintTy::U64 => ty::Uint(ty::UintTy::U64), - chalk_ir::UintTy::U128 => ty::Uint(ty::UintTy::U128), - }, - chalk_ir::Scalar::Float(float_ty) => match float_ty { - chalk_ir::FloatTy::F32 => ty::Float(ty::FloatTy::F32), - chalk_ir::FloatTy::F64 => ty::Float(ty::FloatTy::F64), - }, - }, - TyKind::Array(ty, c) => { - let ty = ty.lower_into(interner); - let c = c.lower_into(interner); - ty::Array(ty, c) - } - TyKind::FnDef(id, substitution) => ty::FnDef(id.0, substitution.lower_into(interner)), - TyKind::Closure(closure, substitution) => { - ty::Closure(closure.0, substitution.lower_into(interner)) - } - TyKind::Generator(generator, substitution) => ty::Generator( - generator.0, - substitution.lower_into(interner), - ast::Movability::Static, - ), - TyKind::GeneratorWitness(..) => unimplemented!(), - TyKind::Never => ty::Never, - TyKind::Tuple(_len, substitution) => { - ty::Tuple(substitution.lower_into(interner).into_type_list(interner.tcx)) - } - TyKind::Slice(ty) => ty::Slice(ty.lower_into(interner)), - TyKind::Raw(mutbl, ty) => ty::RawPtr(ty::TypeAndMut { - ty: ty.lower_into(interner), - mutbl: mutbl.lower_into(interner), - }), - TyKind::Ref(mutbl, lifetime, ty) => ty::Ref( - lifetime.lower_into(interner), - ty.lower_into(interner), - mutbl.lower_into(interner), - ), - TyKind::Str => ty::Str, - TyKind::OpaqueType(opaque_ty, substitution) => ty::Alias( - ty::Opaque, - interner.tcx.mk_alias_ty(opaque_ty.0, substitution.lower_into(interner)), - ), - TyKind::AssociatedType(assoc_ty, substitution) => ty::Alias( - ty::Projection, - interner.tcx.mk_alias_ty(assoc_ty.0, substitution.lower_into(interner)), - ), - TyKind::Foreign(def_id) => ty::Foreign(def_id.0), - TyKind::Error => return interner.tcx.ty_error_misc(), - TyKind::Alias(alias_ty) => match alias_ty { - chalk_ir::AliasTy::Projection(projection) => ty::Alias( - ty::Projection, - interner.tcx.mk_alias_ty( - projection.associated_ty_id.0, - projection.substitution.lower_into(interner), - ), - ), - chalk_ir::AliasTy::Opaque(opaque) => ty::Alias( - ty::Opaque, - interner.tcx.mk_alias_ty( - opaque.opaque_ty_id.0, - opaque.substitution.lower_into(interner), - ), - ), - }, - TyKind::Function(_quantified_ty) => unimplemented!(), - TyKind::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, - }, - ), - TyKind::Placeholder(placeholder) => ty::Placeholder(ty::Placeholder { - universe: ty::UniverseIndex::from_usize(placeholder.ui.counter), - bound: ty::BoundTy { - var: ty::BoundVar::from_usize(placeholder.idx), - kind: ty::BoundTyKind::Anon, - }, - }), - TyKind::InferenceVar(_, _) => unimplemented!(), - TyKind::Dyn(_) => unimplemented!(), - }; - interner.tcx.mk_ty_from_kind(kind) - } -} - -impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime<RustInterner<'tcx>>> for Region<'tcx> { - fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Lifetime<RustInterner<'tcx>> { - match *self { - ty::ReEarlyBound(_) => { - panic!("Should have already been substituted."); - } - ty::ReError(_) => { - panic!("Error lifetime should not have already been lowered."); - } - ty::ReLateBound(db, br) => chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new( - chalk_ir::DebruijnIndex::new(db.as_u32()), - br.var.as_usize(), - )) - .intern(interner), - ty::ReFree(_) => unimplemented!(), - ty::ReStatic => chalk_ir::LifetimeData::Static.intern(interner), - ty::ReVar(_) => unimplemented!(), - ty::RePlaceholder(placeholder_region) => { - chalk_ir::LifetimeData::Placeholder(chalk_ir::PlaceholderIndex { - ui: chalk_ir::UniverseIndex { counter: placeholder_region.universe.index() }, - idx: 0, // FIXME: This `idx: 0` is sus. - }) - .intern(interner) - } - ty::ReErased => chalk_ir::LifetimeData::Erased.intern(interner), - } - } -} - -impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime<RustInterner<'tcx>> { - fn lower_into(self, interner: RustInterner<'tcx>) -> Region<'tcx> { - let tcx = interner.tcx; - match self.data(interner) { - chalk_ir::LifetimeData::BoundVar(var) => ty::Region::new_late_bound( - tcx, - ty::DebruijnIndex::from_u32(var.debruijn.depth()), - ty::BoundRegion { - var: ty::BoundVar::from_usize(var.index), - kind: ty::BrAnon(None), - }, - ), - chalk_ir::LifetimeData::InferenceVar(_var) => unimplemented!(), - chalk_ir::LifetimeData::Placeholder(p) => ty::Region::new_placeholder( - tcx, - ty::Placeholder { - universe: ty::UniverseIndex::from_usize(p.ui.counter), - bound: ty::BoundRegion { - var: ty::BoundVar::from_usize(p.idx), - kind: ty::BoundRegionKind::BrAnon(None), - }, - }, - ), - chalk_ir::LifetimeData::Static => tcx.lifetimes.re_static, - chalk_ir::LifetimeData::Erased => tcx.lifetimes.re_erased, - chalk_ir::LifetimeData::Phantom(void, _) => match *void {}, - } - } -} - -impl<'tcx> LowerInto<'tcx, chalk_ir::Const<RustInterner<'tcx>>> for ty::Const<'tcx> { - fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Const<RustInterner<'tcx>> { - let ty = self.ty().lower_into(interner); - let value = match self.kind() { - 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<RustInterner<'tcx>> { - fn lower_into(self, interner: RustInterner<'tcx>) -> ty::Const<'tcx> { - let data = self.data(interner); - let ty = data.ty.lower_into(interner); - let kind = 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), - }; - interner.tcx.mk_const(kind, ty) - } -} - -impl<'tcx> LowerInto<'tcx, chalk_ir::GenericArg<RustInterner<'tcx>>> for GenericArg<'tcx> { - fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::GenericArg<RustInterner<'tcx>> { - match self.unpack() { - ty::subst::GenericArgKind::Type(ty) => { - chalk_ir::GenericArgData::Ty(ty.lower_into(interner)) - } - ty::subst::GenericArgKind::Lifetime(lifetime) => { - chalk_ir::GenericArgData::Lifetime(lifetime.lower_into(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<RustInterner<'tcx>> -{ - 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); - 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 -// eventually be removed. -impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>> - for ty::Predicate<'tcx> -{ - fn lower_into( - self, - interner: RustInterner<'tcx>, - ) -> Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>> { - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, self.kind()); - let value = match predicate { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { - Some(chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner))) - } - ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => { - Some(chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { - a: predicate.0.lower_into(interner), - b: predicate.1.lower_into(interner), - })) - } - ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => { - Some(chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { - ty: predicate.0.lower_into(interner), - lifetime: predicate.1.lower_into(interner), - })) - } - ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => { - Some(chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner))) - } - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_ty)) => None, - ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => None, - - ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Subtype(..) - | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::Ambiguous - | ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => { - bug!("unexpected predicate {self}") - } - }; - value.map(|value| chalk_ir::Binders::new(binders, value)) - } -} - -impl<'tcx> LowerInto<'tcx, chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<RustInterner<'tcx>>>> - for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> -{ - fn lower_into( - self, - interner: RustInterner<'tcx>, - ) -> chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<RustInterner<'tcx>>> { - // `Self` has one binder: - // Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>> - // The return type has two: - // Binders<&[Binders<WhereClause<I>>]> - // This means that any variables that are escaping `self` need to be - // shifted in by one so that they are still escaping. - let predicates = ty::fold::shift_vars(interner.tcx, self, 1); - - let self_ty = interner.tcx.mk_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| { - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, predicate); - match predicate { - ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { def_id, substs }) => { - chalk_ir::Binders::new( - binders.clone(), - chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef { - trait_id: chalk_ir::TraitId(def_id), - substitution: interner - .tcx - .mk_substs_trait(self_ty, substs) - .lower_into(interner), - }), - ) - } - ty::ExistentialPredicate::Projection(predicate) => chalk_ir::Binders::new( - binders.clone(), - chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { - alias: chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { - associated_ty_id: chalk_ir::AssocTypeId(predicate.def_id), - substitution: interner - .tcx - .mk_substs_trait(self_ty, predicate.substs) - .lower_into(interner), - }), - // FIXME(associated_const_equality): teach chalk about terms for alias eq. - ty: predicate.term.ty().unwrap().lower_into(interner), - }), - ), - ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new( - binders.clone(), - chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef { - trait_id: chalk_ir::TraitId(def_id), - substitution: interner - .tcx - .mk_substs_trait(self_ty, []) - .lower_into(interner), - }), - ), - } - }); - - // Binder for the bound variable representing the concrete underlying type. - let existential_binder = chalk_ir::VariableKinds::from1( - interner, - chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), - ); - let value = chalk_ir::QuantifiedWhereClauses::from_iter(interner, where_clauses); - chalk_ir::Binders::new(existential_binder, value) - } -} - -impl<'tcx> LowerInto<'tcx, chalk_ir::FnSig<RustInterner<'tcx>>> - for ty::Binder<'tcx, ty::FnSig<'tcx>> -{ - fn lower_into(self, _interner: RustInterner<'_>) -> FnSig<RustInterner<'tcx>> { - chalk_ir::FnSig { - abi: self.abi(), - safety: match self.unsafety() { - Unsafety::Normal => chalk_ir::Safety::Safe, - Unsafety::Unsafe => chalk_ir::Safety::Unsafe, - }, - variadic: self.c_variadic(), - } - } -} - -// We lower into an Option here since there are some predicates which Chalk -// doesn't have a representation for yet (as an `InlineBound`). The `Option` will -// eventually be removed. -impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<RustInterner<'tcx>>>> - for ty::Predicate<'tcx> -{ - fn lower_into( - self, - interner: RustInterner<'tcx>, - ) -> Option<chalk_solve::rust_ir::QuantifiedInlineBound<RustInterner<'tcx>>> { - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, self.kind()); - match predicate { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { - Some(chalk_ir::Binders::new( - binders, - chalk_solve::rust_ir::InlineBound::TraitBound( - predicate.trait_ref.lower_into(interner), - ), - )) - } - ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => { - Some(chalk_ir::Binders::new( - binders, - chalk_solve::rust_ir::InlineBound::AliasEqBound(predicate.lower_into(interner)), - )) - } - ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(_predicate)) => None, - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_ty)) => None, - ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => None, - - ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) - | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Subtype(..) - | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::Ambiguous - | ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => { - bug!("unexpected predicate {}", &self) - } - } - } -} - -impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::TraitBound<RustInterner<'tcx>>> - for ty::TraitRef<'tcx> -{ - fn lower_into( - self, - interner: RustInterner<'tcx>, - ) -> chalk_solve::rust_ir::TraitBound<RustInterner<'tcx>> { - chalk_solve::rust_ir::TraitBound { - trait_id: chalk_ir::TraitId(self.def_id), - args_no_self: self.substs[1..].iter().map(|arg| arg.lower_into(interner)).collect(), - } - } -} - -impl<'tcx> LowerInto<'tcx, chalk_ir::Mutability> for ast::Mutability { - fn lower_into(self, _interner: RustInterner<'tcx>) -> chalk_ir::Mutability { - match self { - rustc_ast::Mutability::Mut => chalk_ir::Mutability::Mut, - rustc_ast::Mutability::Not => chalk_ir::Mutability::Not, - } - } -} - -impl<'tcx> LowerInto<'tcx, ast::Mutability> for chalk_ir::Mutability { - fn lower_into(self, _interner: RustInterner<'tcx>) -> ast::Mutability { - match self { - chalk_ir::Mutability::Mut => ast::Mutability::Mut, - chalk_ir::Mutability::Not => ast::Mutability::Not, - } - } -} - -impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::Polarity> for ty::ImplPolarity { - fn lower_into(self, _interner: RustInterner<'tcx>) -> chalk_solve::rust_ir::Polarity { - match self { - ty::ImplPolarity::Positive => chalk_solve::rust_ir::Polarity::Positive, - ty::ImplPolarity::Negative => chalk_solve::rust_ir::Polarity::Negative, - // FIXME(chalk) reservation impls - ty::ImplPolarity::Reservation => chalk_solve::rust_ir::Polarity::Negative, - } - } -} -impl<'tcx> LowerInto<'tcx, chalk_ir::Variance> for ty::Variance { - fn lower_into(self, _interner: RustInterner<'tcx>) -> chalk_ir::Variance { - match self { - ty::Variance::Covariant => chalk_ir::Variance::Covariant, - ty::Variance::Invariant => chalk_ir::Variance::Invariant, - ty::Variance::Contravariant => chalk_ir::Variance::Contravariant, - ty::Variance::Bivariant => unimplemented!(), - } - } -} - -impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>>> - for ty::ProjectionPredicate<'tcx> -{ - fn lower_into( - self, - interner: RustInterner<'tcx>, - ) -> chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>> { - let (trait_ref, own_substs) = self.projection_ty.trait_ref_and_own_substs(interner.tcx); - chalk_solve::rust_ir::AliasEqBound { - trait_bound: trait_ref.lower_into(interner), - associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.def_id), - parameters: own_substs.iter().map(|arg| arg.lower_into(interner)).collect(), - value: self.term.ty().unwrap().lower_into(interner), - } - } -} - -/// To collect bound vars, we have to do two passes. In the first pass, we -/// collect all `BoundRegionKind`s and `ty::Bound`s. In the second pass, we then -/// replace `BrNamed` into `BrAnon`. The two separate passes are important, -/// since we can only replace `BrNamed` with `BrAnon`s with indices *after* all -/// "real" `BrAnon`s. -/// -/// It's important to note that because of prior substitution, we may have -/// late-bound regions, even outside of fn contexts, since this is the best way -/// to prep types for chalk lowering. -pub(crate) fn collect_bound_vars<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( - interner: RustInterner<'tcx>, - tcx: TyCtxt<'tcx>, - ty: Binder<'tcx, T>, -) -> (T, chalk_ir::VariableKinds<RustInterner<'tcx>>, BTreeMap<DefId, u32>) { - let mut bound_vars_collector = BoundVarsCollector::new(); - ty.as_ref().skip_binder().visit_with(&mut bound_vars_collector); - let mut parameters = bound_vars_collector.parameters; - let named_parameters: BTreeMap<DefId, u32> = bound_vars_collector - .named_parameters - .into_iter() - .enumerate() - .map(|(i, def_id)| (def_id, (i + parameters.len()) as u32)) - .collect(); - - let mut bound_var_substitutor = NamedBoundVarSubstitutor::new(tcx, &named_parameters); - let new_ty = ty.skip_binder().fold_with(&mut bound_var_substitutor); - - for var in named_parameters.values() { - parameters.insert(*var, chalk_ir::VariableKind::Lifetime); - } - - (0..parameters.len()).for_each(|i| { - parameters - .get(&(i as u32)) - .or_else(|| bug!("Skipped bound var index: parameters={:?}", parameters)); - }); - - let binders = chalk_ir::VariableKinds::from_iter(interner, parameters.into_values()); - - (new_ty, binders, named_parameters) -} - -pub(crate) struct BoundVarsCollector<'tcx> { - binder_index: ty::DebruijnIndex, - pub(crate) parameters: BTreeMap<u32, chalk_ir::VariableKind<RustInterner<'tcx>>>, - pub(crate) named_parameters: Vec<DefId>, -} - -impl<'tcx> BoundVarsCollector<'tcx> { - pub(crate) fn new() -> Self { - BoundVarsCollector { - binder_index: ty::INNERMOST, - parameters: BTreeMap::new(), - named_parameters: vec![], - } - } -} - -impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for BoundVarsCollector<'tcx> { - fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>( - &mut self, - t: &Binder<'tcx, T>, - ) -> ControlFlow<Self::BreakTy> { - self.binder_index.shift_in(1); - let result = t.super_visit_with(self); - self.binder_index.shift_out(1); - result - } - - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { - match *t.kind() { - ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { - match self.parameters.entry(bound_ty.var.as_u32()) { - Entry::Vacant(entry) => { - entry.insert(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)); - } - Entry::Occupied(entry) => match entry.get() { - chalk_ir::VariableKind::Ty(_) => {} - _ => panic!(), - }, - } - } - - _ => (), - }; - - t.super_visit_with(self) - } - - fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> { - match *r { - ty::ReLateBound(index, br) if index == self.binder_index => match br.kind { - ty::BoundRegionKind::BrNamed(def_id, _name) => { - if !self.named_parameters.iter().any(|d| *d == def_id) { - self.named_parameters.push(def_id); - } - } - - ty::BoundRegionKind::BrAnon(_) => match self.parameters.entry(br.var.as_u32()) { - Entry::Vacant(entry) => { - entry.insert(chalk_ir::VariableKind::Lifetime); - } - Entry::Occupied(entry) => match entry.get() { - chalk_ir::VariableKind::Lifetime => {} - _ => panic!(), - }, - }, - - ty::BoundRegionKind::BrEnv => unimplemented!(), - }, - - ty::ReEarlyBound(_re) => { - // FIXME(chalk): jackh726 - I think we should always have already - // substituted away `ReEarlyBound`s for `ReLateBound`s, but need to confirm. - unimplemented!(); - } - - _ => (), - }; - - ControlFlow::Continue(()) - } -} - -/// This is used to replace `BoundRegionKind::BrNamed` with `BoundRegionKind::BrAnon`. -/// Note: we assume that we will always have room for more bound vars. (i.e. we -/// won't ever hit the `u32` limit in `BrAnon`s). -struct NamedBoundVarSubstitutor<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - binder_index: ty::DebruijnIndex, - named_parameters: &'a BTreeMap<DefId, u32>, -} - -impl<'a, 'tcx> NamedBoundVarSubstitutor<'a, 'tcx> { - fn new(tcx: TyCtxt<'tcx>, named_parameters: &'a BTreeMap<DefId, u32>) -> Self { - NamedBoundVarSubstitutor { tcx, binder_index: ty::INNERMOST, named_parameters } - } -} - -impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for NamedBoundVarSubstitutor<'a, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>( - &mut self, - t: Binder<'tcx, T>, - ) -> Binder<'tcx, T> { - self.binder_index.shift_in(1); - let result = t.super_fold_with(self); - self.binder_index.shift_out(1); - result - } - - fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> { - match *r { - ty::ReLateBound(index, br) if index == self.binder_index => match br.kind { - ty::BrNamed(def_id, _name) => match self.named_parameters.get(&def_id) { - Some(_) => { - let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(None) }; - return ty::Region::new_late_bound(self.tcx, index, new_br); - } - None => panic!("Missing `BrNamed`."), - }, - ty::BrEnv => unimplemented!(), - ty::BrAnon(..) => {} - }, - _ => (), - }; - - r - } -} - -/// Used to substitute `Param`s with placeholders. We do this since Chalk -/// have a notion of `Param`s. -pub(crate) struct ParamsSubstitutor<'tcx> { - tcx: TyCtxt<'tcx>, - binder_index: ty::DebruijnIndex, - list: Vec<rustc_middle::ty::ParamTy>, - next_ty_placeholder: usize, - pub(crate) params: rustc_data_structures::fx::FxHashMap<u32, rustc_middle::ty::ParamTy>, - pub(crate) named_regions: BTreeMap<DefId, u32>, -} - -impl<'tcx> ParamsSubstitutor<'tcx> { - pub(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(), - } - } -} - -impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ParamsSubstitutor<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>( - &mut self, - t: Binder<'tcx, T>, - ) -> Binder<'tcx, T> { - self.binder_index.shift_in(1); - let result = t.super_fold_with(self); - self.binder_index.shift_out(1); - result - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match *t.kind() { - ty::Param(param) => match self.list.iter().position(|r| r == ¶m) { - Some(idx) => self.tcx.mk_placeholder(ty::PlaceholderType { - universe: ty::UniverseIndex::from_usize(0), - bound: ty::BoundTy { - var: ty::BoundVar::from_usize(idx), - kind: ty::BoundTyKind::Anon, - }, - }), - None => { - self.list.push(param); - let idx = self.list.len() - 1 + self.next_ty_placeholder; - self.params.insert(idx as u32, param); - self.tcx.mk_placeholder(ty::PlaceholderType { - universe: ty::UniverseIndex::from_usize(0), - bound: ty::BoundTy { - var: ty::BoundVar::from_usize(idx), - kind: ty::BoundTyKind::Anon, - }, - }) - } - }, - _ => t.super_fold_with(self), - } - } - - fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> { - match *r { - // FIXME(chalk) - jackh726 - this currently isn't hit in any tests, - // since canonicalization will already change these to canonical - // variables (ty::ReLateBound). - ty::ReEarlyBound(_re) => match self.named_regions.get(&_re.def_id) { - Some(idx) => { - let br = ty::BoundRegion { - var: ty::BoundVar::from_u32(*idx), - kind: ty::BrAnon(None), - }; - ty::Region::new_late_bound(self.tcx, self.binder_index, br) - } - None => { - let idx = self.named_regions.len() as u32; - let br = ty::BoundRegion { - var: ty::BoundVar::from_u32(idx), - kind: ty::BrAnon(None), - }; - self.named_regions.insert(_re.def_id, idx); - ty::Region::new_late_bound(self.tcx, self.binder_index, br) - } - }, - - _ => r, - } - } -} - -pub(crate) struct ReverseParamsSubstitutor<'tcx> { - tcx: TyCtxt<'tcx>, - params: rustc_data_structures::fx::FxHashMap<u32, rustc_middle::ty::ParamTy>, -} - -impl<'tcx> ReverseParamsSubstitutor<'tcx> { - pub(crate) fn new( - tcx: TyCtxt<'tcx>, - params: rustc_data_structures::fx::FxHashMap<u32, rustc_middle::ty::ParamTy>, - ) -> Self { - Self { tcx, params } - } -} - -impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseParamsSubstitutor<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match *t.kind() { - ty::Placeholder(ty::PlaceholderType { universe: ty::UniverseIndex::ROOT, bound }) => { - match self.params.get(&bound.var.as_u32()) { - Some(&ty::ParamTy { index, name }) => self.tcx.mk_ty_param(index, name), - None => t, - } - } - - _ => t.super_fold_with(self), - } - } -} - -/// Used to collect `Placeholder`s. -pub(crate) struct PlaceholdersCollector { - universe_index: ty::UniverseIndex, - pub(crate) next_ty_placeholder: usize, - pub(crate) next_anon_region_placeholder: u32, -} - -impl PlaceholdersCollector { - pub(crate) fn new() -> Self { - PlaceholdersCollector { - universe_index: ty::UniverseIndex::ROOT, - next_ty_placeholder: 0, - next_anon_region_placeholder: 0, - } - } -} - -impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for PlaceholdersCollector { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { - match t.kind() { - ty::Placeholder(p) if p.universe == self.universe_index => { - self.next_ty_placeholder = self.next_ty_placeholder.max(p.bound.var.as_usize() + 1); - } - - _ => (), - }; - - t.super_visit_with(self) - } - - fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> { - match *r { - ty::RePlaceholder(p) if p.universe == self.universe_index => { - if let ty::BoundRegionKind::BrAnon(_) = p.bound.kind { - self.next_anon_region_placeholder = - self.next_anon_region_placeholder.max(p.bound.var.as_u32()); - } - // FIXME: This doesn't seem to handle BrNamed at all? - } - - _ => (), - }; - - ControlFlow::Continue(()) - } -} diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs deleted file mode 100644 index 8834449c9a4..00000000000 --- a/compiler/rustc_traits/src/chalk/mod.rs +++ /dev/null @@ -1,169 +0,0 @@ -//! Calls `chalk-solve` to solve a `ty::Predicate` -//! -//! In order to call `chalk-solve`, this file must convert a `CanonicalChalkEnvironmentAndGoal` into -//! a Chalk uncanonical goal. It then calls Chalk, and converts the answer back into rustc solution. - -pub(crate) mod db; -pub(crate) mod lowering; - -use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind}; -use rustc_middle::query::Providers; -use rustc_middle::traits::ChalkRustInterner; -use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitable}; - -use rustc_infer::infer::canonical::{ - Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse, -}; -use rustc_infer::traits::{self, CanonicalChalkEnvironmentAndGoal}; - -use crate::chalk::db::RustIrDatabase as ChalkRustIrDatabase; -use crate::chalk::lowering::LowerInto; -use crate::chalk::lowering::{ParamsSubstitutor, PlaceholdersCollector, ReverseParamsSubstitutor}; - -use chalk_solve::Solution; - -pub(crate) fn provide(p: &mut Providers) { - *p = Providers { evaluate_goal, ..*p }; -} - -pub(crate) fn evaluate_goal<'tcx>( - tcx: TyCtxt<'tcx>, - obligation: CanonicalChalkEnvironmentAndGoal<'tcx>, -) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, traits::query::NoSolution> { - let interner = ChalkRustInterner { tcx }; - - // Chalk doesn't have a notion of `Params`, so instead we use placeholders. - let mut placeholders_collector = PlaceholdersCollector::new(); - obligation.visit_with(&mut placeholders_collector); - - let mut params_substitutor = - ParamsSubstitutor::new(tcx, placeholders_collector.next_ty_placeholder); - let obligation = obligation.fold_with(&mut params_substitutor); - let params = params_substitutor.params; - - let max_universe = obligation.max_universe.index(); - - let lowered_goal: chalk_ir::UCanonical< - chalk_ir::InEnvironment<chalk_ir::Goal<ChalkRustInterner<'tcx>>>, - > = chalk_ir::UCanonical { - canonical: chalk_ir::Canonical { - binders: chalk_ir::CanonicalVarKinds::from_iter( - interner, - obligation.variables.iter().map(|v| match v.kind { - CanonicalVarKind::PlaceholderTy(_ty) => unimplemented!(), - CanonicalVarKind::PlaceholderRegion(_ui) => unimplemented!(), - CanonicalVarKind::Ty(ty) => match ty { - CanonicalTyVarKind::General(ui) => chalk_ir::WithKind::new( - chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), - chalk_ir::UniverseIndex { counter: ui.index() }, - ), - CanonicalTyVarKind::Int => chalk_ir::WithKind::new( - chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::Integer), - chalk_ir::UniverseIndex::root(), - ), - CanonicalTyVarKind::Float => chalk_ir::WithKind::new( - chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::Float), - chalk_ir::UniverseIndex::root(), - ), - }, - CanonicalVarKind::Region(ui) => chalk_ir::WithKind::new( - chalk_ir::VariableKind::Lifetime, - chalk_ir::UniverseIndex { counter: ui.index() }, - ), - CanonicalVarKind::Const(_ui, _ty) => unimplemented!(), - CanonicalVarKind::PlaceholderConst(_pc, _ty) => unimplemented!(), - }), - ), - value: obligation.value.lower_into(interner), - }, - universes: max_universe + 1, - }; - - use chalk_solve::Solver; - let mut solver = chalk_engine::solve::SLGSolver::new(32, None); - let db = ChalkRustIrDatabase { interner }; - debug!(?lowered_goal); - let solution = solver.solve(&db, &lowered_goal); - debug!(?obligation, ?solution, "evaluate 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<_>, - binders: chalk_ir::CanonicalVarKinds<_>| { - use rustc_middle::infer::canonical::CanonicalVarInfo; - - let mut reverse_param_substitutor = ReverseParamsSubstitutor::new(tcx, params); - let var_values = tcx.mk_substs_from_iter( - subst - .as_slice(interner) - .iter() - .map(|p| p.lower_into(interner).fold_with(&mut reverse_param_substitutor)), - ); - let variables = binders.iter(interner).map(|var| { - let kind = match var.kind { - chalk_ir::VariableKind::Ty(ty_kind) => CanonicalVarKind::Ty(match ty_kind { - chalk_ir::TyVariableKind::General => CanonicalTyVarKind::General( - ty::UniverseIndex::from_usize(var.skip_kind().counter), - ), - chalk_ir::TyVariableKind::Integer => CanonicalTyVarKind::Int, - chalk_ir::TyVariableKind::Float => CanonicalTyVarKind::Float, - }), - chalk_ir::VariableKind::Lifetime => { - CanonicalVarKind::Region(ty::UniverseIndex::from_usize(var.skip_kind().counter)) - } - // FIXME(compiler-errors): We don't currently have a way of turning - // a Chalk ty back into a rustc ty, right? - chalk_ir::VariableKind::Const(_) => todo!(), - }; - CanonicalVarInfo { kind } - }); - let max_universe = binders.iter(interner).map(|v| v.skip_kind().counter).max().unwrap_or(0); - let sol = Canonical { - max_universe: ty::UniverseIndex::from_usize(max_universe), - variables: tcx.mk_canonical_var_infos_from_iter(variables), - value: QueryResponse { - var_values: CanonicalVarValues { var_values }, - region_constraints: QueryRegionConstraints::default(), - certainty: Certainty::Proven, - opaque_types: vec![], - value: (), - }, - }; - tcx.arena.alloc(sol) - }; - solution - .map(|s| match s { - Solution::Unique(subst) => { - // FIXME(chalk): handle constraints - make_solution(subst.value.subst, subst.binders) - } - Solution::Ambig(guidance) => { - match guidance { - chalk_solve::Guidance::Definite(subst) => { - make_solution(subst.value, subst.binders) - } - chalk_solve::Guidance::Suggested(_) => unimplemented!(), - chalk_solve::Guidance::Unknown => { - // chalk_fulfill doesn't use the var_values here, so - // let's just ignore that - let sol = Canonical { - max_universe: ty::UniverseIndex::from_usize(0), - variables: obligation.variables, - value: QueryResponse { - var_values: CanonicalVarValues::dummy(), - region_constraints: QueryRegionConstraints::default(), - certainty: Certainty::Ambiguous, - opaque_types: vec![], - value: (), - }, - }; - &*tcx.arena.alloc(sol) - } - } - } - }) - .ok_or(traits::query::NoSolution) -} diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index 590d0bd0e42..dfa5814219b 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -1,5 +1,4 @@ -//! New recursive solver modeled on Chalk's recursive solver. Most of -//! the guts are broken up into modules; see the comments in those modules. +//! Queries that are independent from the main solver code. #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] @@ -11,7 +10,6 @@ extern crate tracing; #[macro_use] extern crate rustc_middle; -mod chalk; mod codegen; mod dropck_outlives; mod evaluate_obligation; @@ -29,7 +27,6 @@ pub fn provide(p: &mut Providers) { dropck_outlives::provide(p); evaluate_obligation::provide(p); implied_outlives_bounds::provide(p); - chalk::provide(p); normalize_projection_ty::provide(p); normalize_erasing_regions::provide(p); type_op::provide(p); diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index b83abf98592..2563e3ed1a3 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -69,7 +69,6 @@ fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool { | ty::PredicateKind::Coerce(..) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::Ambiguous - | ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => true, + | ty::PredicateKind::Ambiguous => true, } } diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml index 51885c9b47e..50dac3a37a4 100644 --- a/compiler/rustc_ty_utils/Cargo.toml +++ b/compiler/rustc_ty_utils/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] tracing = "0.1" +itertools = "0.10.1" rustc_middle = { path = "../rustc_middle" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 8e2a79dd4d4..55484f5c72e 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -64,7 +64,7 @@ fn fn_sig_for_fn_abi<'tcx>( // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`. sig = sig.map_bound(|mut sig| { let mut inputs_and_output = sig.inputs_and_output.to_vec(); - inputs_and_output[0] = tcx.mk_mut_ptr(inputs_and_output[0]); + inputs_and_output[0] = Ty::new_mut_ptr(tcx, inputs_and_output[0]); sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output); sig }); @@ -106,12 +106,13 @@ fn fn_sig_for_fn_abi<'tcx>( var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind: ty::BoundRegionKind::BrEnv, }; - let env_ty = tcx.mk_mut_ref(ty::Region::new_late_bound(tcx, ty::INNERMOST, br), ty); + let env_ty = + Ty::new_mut_ref(tcx, ty::Region::new_late_bound(tcx, ty::INNERMOST, br), ty); let pin_did = tcx.require_lang_item(LangItem::Pin, None); let pin_adt_ref = tcx.adt_def(pin_did); let pin_substs = tcx.mk_substs(&[env_ty.into()]); - let env_ty = tcx.mk_adt(pin_adt_ref, pin_substs); + let env_ty = Ty::new_adt(tcx, pin_adt_ref, pin_substs); let sig = sig.skip_binder(); // The `FnSig` and the `ret_ty` here is for a generators main @@ -123,7 +124,7 @@ fn fn_sig_for_fn_abi<'tcx>( let poll_did = tcx.require_lang_item(LangItem::Poll, None); let poll_adt_ref = tcx.adt_def(poll_did); let poll_substs = tcx.mk_substs(&[sig.return_ty.into()]); - let ret_ty = tcx.mk_adt(poll_adt_ref, poll_substs); + let ret_ty = Ty::new_adt(tcx, poll_adt_ref, poll_substs); // We have to replace the `ResumeTy` that is used for type and borrow checking // with `&mut Context<'_>` which is used in codegen. @@ -137,7 +138,7 @@ fn fn_sig_for_fn_abi<'tcx>( panic!("expected `ResumeTy`, found `{:?}`", sig.resume_ty); }; } - let context_mut_ref = tcx.mk_task_context(); + let context_mut_ref = Ty::new_task_context(tcx); (context_mut_ref, ret_ty) } else { @@ -145,7 +146,7 @@ fn fn_sig_for_fn_abi<'tcx>( let state_did = tcx.require_lang_item(LangItem::GeneratorState, None); let state_adt_ref = tcx.adt_def(state_did); let state_substs = tcx.mk_substs(&[sig.yield_ty.into(), sig.return_ty.into()]); - let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); + let ret_ty = Ty::new_adt(tcx, state_adt_ref, state_substs); (sig.resume_ty, ret_ty) }; @@ -566,7 +567,7 @@ fn make_thin_self_ptr<'tcx>( let fat_pointer_ty = if layout.is_unsized() { // unsized `self` is passed as a pointer to `self` // FIXME (mikeyhew) change this to use &own if it is ever added to the language - tcx.mk_mut_ptr(layout.ty) + Ty::new_mut_ptr(tcx, layout.ty) } else { match layout.abi { Abi::ScalarPair(..) | Abi::Scalar(..) => (), @@ -600,7 +601,7 @@ fn make_thin_self_ptr<'tcx>( // we now have a type like `*mut RcBox<dyn Trait>` // change its layout to that of `*mut ()`, a thin pointer, but keep the same type // this is understood as a special case elsewhere in the compiler - let unit_ptr_ty = tcx.mk_mut_ptr(tcx.mk_unit()); + let unit_ptr_ty = Ty::new_mut_ptr(tcx, Ty::new_unit(tcx)); TyAndLayout { ty: fat_pointer_ty, diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index b59458bbf35..897e7aad48b 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -5,7 +5,7 @@ use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::definitions::DefPathData; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, ImplTraitInTraitData, InternalSubsts, TyCtxt}; +use rustc_middle::ty::{self, ImplTraitInTraitData, InternalSubsts, Ty, TyCtxt}; use rustc_span::symbol::kw; pub fn provide(providers: &mut Providers) { @@ -301,7 +301,8 @@ fn associated_type_for_impl_trait_in_trait( trait_assoc_ty.defaultness(tcx.defaultness(fn_def_id)); // Copy type_of of the opaque. - trait_assoc_ty.type_of(ty::EarlyBinder::bind(tcx.mk_opaque( + trait_assoc_ty.type_of(ty::EarlyBinder::bind(Ty::new_opaque( + tcx, opaque_ty_def_id.to_def_id(), InternalSubsts::identity_for_item(tcx, opaque_ty_def_id), ))); @@ -337,6 +338,7 @@ fn associated_type_for_impl_trait_in_trait( param_def_id_to_index, has_self: opaque_ty_generics.has_self, has_late_bound_regions: opaque_ty_generics.has_late_bound_regions, + host_effect_index: parent_generics.host_effect_index, } }); @@ -415,6 +417,7 @@ fn associated_type_for_impl_trait_in_impl( param_def_id_to_index, has_self: false, has_late_bound_regions: trait_assoc_generics.has_late_bound_regions, + host_effect_index: parent_generics.host_effect_index, } }); diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index d79ed220570..8cc75a6e2e3 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -33,8 +33,10 @@ pub(crate) fn destructure_const<'tcx>( let (fields, variant) = match const_.ty().kind() { ty::Array(inner_ty, _) | ty::Slice(inner_ty) => { // construct the consts for the elements of the array/slice - let field_consts = - branches.iter().map(|b| tcx.mk_const(*b, *inner_ty)).collect::<Vec<_>>(); + let field_consts = branches + .iter() + .map(|b| ty::Const::new_value(tcx, *b, *inner_ty)) + .collect::<Vec<_>>(); debug!(?field_consts); (field_consts, None) @@ -52,7 +54,7 @@ pub(crate) fn destructure_const<'tcx>( for (field, field_valtree) in iter::zip(fields, branches) { let field_ty = field.ty(tcx, substs); - let field_const = tcx.mk_const(*field_valtree, field_ty); + let field_const = ty::Const::new_value(tcx, *field_valtree, field_ty); field_consts.push(field_const); } debug!(?field_consts); @@ -61,7 +63,7 @@ pub(crate) fn destructure_const<'tcx>( } ty::Tuple(elem_tys) => { let fields = iter::zip(*elem_tys, branches) - .map(|(elem_ty, elem_valtree)| tcx.mk_const(*elem_valtree, elem_ty)) + .map(|(elem_ty, elem_valtree)| ty::Const::new_value(tcx, *elem_valtree, elem_ty)) .collect::<Vec<_>>(); (fields, None) @@ -117,7 +119,7 @@ fn recurse_build<'tcx>( let sp = node.span; match tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) { Ok(c) => c, - Err(LitToConstError::Reported(guar)) => tcx.const_error(node.ty, guar), + Err(LitToConstError::Reported(guar)) => ty::Const::new_error(tcx, guar, node.ty), Err(LitToConstError::TypeError) => { bug!("encountered type error in lit_to_const") } @@ -125,17 +127,17 @@ fn recurse_build<'tcx>( } &ExprKind::NonHirLiteral { lit, user_ty: _ } => { let val = ty::ValTree::from_scalar_int(lit); - tcx.mk_const(val, node.ty) + ty::Const::new_value(tcx, val, node.ty) } &ExprKind::ZstLiteral { user_ty: _ } => { let val = ty::ValTree::zst(); - tcx.mk_const(val, node.ty) + ty::Const::new_value(tcx, val, node.ty) } &ExprKind::NamedConst { def_id, substs, user_ty: _ } => { let uneval = ty::UnevaluatedConst::new(def_id, substs); - tcx.mk_const(uneval, node.ty) + ty::Const::new_unevaluated(tcx, uneval, node.ty) } - ExprKind::ConstParam { param, .. } => tcx.mk_const(*param, node.ty), + ExprKind::ConstParam { param, .. } => ty::Const::new_param(tcx, *param, node.ty), ExprKind::Call { fun, args, .. } => { let fun = recurse_build(tcx, body, *fun, root_span)?; @@ -145,16 +147,16 @@ fn recurse_build<'tcx>( new_args.push(recurse_build(tcx, body, id, root_span)?); } let new_args = tcx.mk_const_list(&new_args); - tcx.mk_const(Expr::FunctionCall(fun, new_args), node.ty) + ty::Const::new_expr(tcx, Expr::FunctionCall(fun, new_args), node.ty) } &ExprKind::Binary { op, lhs, rhs } if check_binop(op) => { let lhs = recurse_build(tcx, body, lhs, root_span)?; let rhs = recurse_build(tcx, body, rhs, root_span)?; - tcx.mk_const(Expr::Binop(op, lhs, rhs), node.ty) + ty::Const::new_expr(tcx, Expr::Binop(op, lhs, rhs), node.ty) } &ExprKind::Unary { op, arg } if check_unop(op) => { let arg = recurse_build(tcx, body, arg, root_span)?; - tcx.mk_const(Expr::UnOp(op, arg), node.ty) + ty::Const::new_expr(tcx, Expr::UnOp(op, arg), node.ty) } // This is necessary so that the following compiles: // @@ -175,11 +177,11 @@ fn recurse_build<'tcx>( // This is important so that `N as usize as usize` doesnt unify with `N as usize`. (untested) &ExprKind::Use { source } => { let arg = recurse_build(tcx, body, source, root_span)?; - tcx.mk_const(Expr::Cast(CastKind::Use, arg, node.ty), node.ty) + ty::Const::new_expr(tcx, Expr::Cast(CastKind::Use, arg, node.ty), node.ty) } &ExprKind::Cast { source } => { let arg = recurse_build(tcx, body, source, root_span)?; - tcx.mk_const(Expr::Cast(CastKind::As, arg, node.ty), node.ty) + ty::Const::new_expr(tcx, Expr::Cast(CastKind::As, arg, node.ty), node.ty) } ExprKind::Borrow { arg, .. } => { let arg_node = &body.exprs[*arg]; diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index 081be065864..10dec9a7a32 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -1,45 +1,56 @@ -use rustc_hir::{def::DefKind, def_id::DefId}; +use rustc_hir as hir; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::LocalDefId; use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::Span; +use std::iter; pub fn provide(providers: &mut Providers) { *providers = Providers { assumed_wf_types, ..*providers }; } -fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> { +fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'tcx>, Span)] { match tcx.def_kind(def_id) { DefKind::Fn => { let sig = tcx.fn_sig(def_id).subst_identity(); - let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig); - liberated_sig.inputs_and_output + let liberated_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig); + tcx.arena.alloc_from_iter(itertools::zip_eq( + liberated_sig.inputs_and_output, + fn_sig_spans(tcx, def_id), + )) } DefKind::AssocFn => { let sig = tcx.fn_sig(def_id).subst_identity(); - let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig); + let liberated_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig); let mut assumed_wf_types: Vec<_> = - tcx.assumed_wf_types(tcx.parent(def_id)).as_slice().into(); - assumed_wf_types.extend(liberated_sig.inputs_and_output); - tcx.mk_type_list(&assumed_wf_types) + tcx.assumed_wf_types(tcx.local_parent(def_id)).into(); + assumed_wf_types.extend(itertools::zip_eq( + liberated_sig.inputs_and_output, + fn_sig_spans(tcx, def_id), + )); + tcx.arena.alloc_slice(&assumed_wf_types) } DefKind::Impl { .. } => { - match tcx.impl_trait_ref(def_id) { - Some(trait_ref) => { - let types: Vec<_> = trait_ref.skip_binder().substs.types().collect(); - tcx.mk_type_list(&types) - } - // Only the impl self type - None => tcx.mk_type_list(&[tcx.type_of(def_id).subst_identity()]), - } + // Trait arguments and the self type for trait impls or only the self type for + // inherent impls. + let tys = match tcx.impl_trait_ref(def_id) { + Some(trait_ref) => trait_ref.skip_binder().substs.types().collect(), + None => vec![tcx.type_of(def_id).subst_identity()], + }; + + let mut impl_spans = impl_spans(tcx, def_id); + tcx.arena.alloc_from_iter(tys.into_iter().map(|ty| (ty, impl_spans.next().unwrap()))) } - DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)), - DefKind::OpaqueTy => match tcx.def_kind(tcx.parent(def_id)) { + DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)), + DefKind::OpaqueTy => match tcx.def_kind(tcx.local_parent(def_id)) { DefKind::TyAlias => ty::List::empty(), - DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)), + DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)), // Nested opaque types only occur in associated types: // ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; ` // assumed_wf_types should include those of `Opaque<T>`, `Opaque<T>` itself // and `&'static T`. - DefKind::OpaqueTy => bug!("unimplemented implied bounds for neseted opaque types"), + DefKind::OpaqueTy => bug!("unimplemented implied bounds for nested opaque types"), def_kind @ _ => { bug!("unimplemented implied bounds for opaque types with parent {def_kind:?}") } @@ -72,3 +83,28 @@ fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> { | DefKind::Generator => ty::List::empty(), } } + +fn fn_sig_spans(tcx: TyCtxt<'_>, def_id: LocalDefId) -> impl Iterator<Item = Span> + '_ { + let node = tcx.hir().get(tcx.local_def_id_to_hir_id(def_id)); + if let Some(decl) = node.fn_decl() { + decl.inputs.iter().map(|ty| ty.span).chain(iter::once(decl.output.span())) + } else { + bug!("unexpected item for fn {def_id:?}: {node:?}") + } +} + +fn impl_spans(tcx: TyCtxt<'_>, def_id: LocalDefId) -> impl Iterator<Item = Span> + '_ { + let item = tcx.hir().expect_item(def_id); + if let hir::ItemKind::Impl(impl_) = item.kind { + let trait_args = impl_ + .of_trait + .into_iter() + .flat_map(|trait_ref| trait_ref.path.segments.last().unwrap().args().args) + .map(|arg| arg.span()); + let dummy_spans_for_default_args = + impl_.of_trait.into_iter().flat_map(|trait_ref| iter::repeat(trait_ref.path.span)); + iter::once(impl_.self_ty.span).chain(trait_args).chain(dummy_spans_for_default_args) + } else { + bug!("unexpected item for impl {def_id:?}: {item:?}") + } +} diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index ac015ddcb49..9ef9120e294 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -159,7 +159,7 @@ fn layout_of_uncached<'tcx>( // fall back to structurally deducing metadata. && !pointee.references_error() { - let pointee_metadata = tcx.mk_projection(metadata_def_id, [pointee]); + let pointee_metadata = Ty::new_projection(tcx,metadata_def_id, [pointee]); let metadata_ty = match tcx.try_normalize_erasing_regions( param_env, pointee_metadata, @@ -672,7 +672,7 @@ fn generator_layout<'tcx>( let promoted_layouts = ineligible_locals .iter() .map(|local| subst_field(info.field_tys[local].ty)) - .map(|ty| tcx.mk_maybe_uninit(ty)) + .map(|ty| Ty::new_maybe_uninit(tcx, ty)) .map(|ty| Ok(cx.layout_of(ty)?.layout)); let prefix_layouts = substs .as_generator() diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 2b391f94a63..466616cd22b 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -1,13 +1,11 @@ -use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_index::bit_set::BitSet; use rustc_middle::query::Providers; use rustc_middle::ty::{ - self, EarlyBinder, ImplTraitInTraitData, ToPredicate, Ty, TyCtxt, TypeSuperVisitable, - TypeVisitable, TypeVisitor, + self, EarlyBinder, ToPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; -use rustc_session::config::TraitSolver; use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_span::DUMMY_SP; use rustc_trait_selection::traits; @@ -97,7 +95,7 @@ fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness { fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] { if let Some(def_id) = def_id.as_local() { if matches!(tcx.representability(def_id), ty::Representability::Infinite) { - return tcx.mk_type_list(&[tcx.ty_error_misc()]); + return tcx.mk_type_list(&[Ty::new_misc_error(tcx)]); } } let def = tcx.adt_def(def_id); @@ -120,22 +118,6 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { let ty::InstantiatedPredicates { mut predicates, .. } = tcx.predicates_of(def_id).instantiate_identity(tcx); - // When computing the param_env of an RPITIT, use predicates of the containing function, - // *except* for the additional assumption that the RPITIT normalizes to the trait method's - // default opaque type. This is needed to properly check the item bounds of the assoc - // type hold (`check_type_bounds`), since that method already installs a similar projection - // bound, so they will conflict. - // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): I don't like this, we should - // at least be making sure that the generics in RPITITs and their parent fn don't - // get out of alignment, or else we do actually need to substitute these predicates. - if let Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) - | Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) = tcx.opt_rpitit_info(def_id) - { - // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): Should not need to add the predicates - // from the parent fn to our assumptions - predicates.extend(tcx.predicates_of(fn_def_id).instantiate_identity(tcx).predicates); - } - // Finally, we have to normalize the bounds in the environment, in // case they contain any associated type projections. This process // can yield errors if the put in illegal associated types, like @@ -148,11 +130,6 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { // are any errors at that point, so outside of type inference you can be // sure that this will succeed without errors anyway. - if tcx.sess.opts.unstable_opts.trait_solver == TraitSolver::Chalk { - let environment = well_formed_types_in_env(tcx, def_id); - predicates.extend(environment); - } - if tcx.def_kind(def_id) == DefKind::AssocFn && tcx.associated_item(def_id).container == ty::AssocItemContainer::TraitContainer { @@ -308,7 +285,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { let default_ty = if self.tcx.lower_impl_trait_in_trait_to_assoc_ty() { self.tcx.type_of(shifted_alias_ty.def_id).subst(self.tcx, shifted_alias_ty.substs) } else { - self.tcx.mk_alias(ty::Opaque, shifted_alias_ty) + Ty::new_alias(self.tcx,ty::Opaque, shifted_alias_ty) }; self.predicates.push( @@ -336,116 +313,6 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { } } -/// Elaborate the environment. -/// -/// Collect a list of `Predicate`'s used for building the `ParamEnv`. Adds `TypeWellFormedFromEnv`'s -/// that are assumed to be well-formed (because they come from the environment). -/// -/// Used only in chalk mode. -fn well_formed_types_in_env(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<ty::Clause<'_>> { - use rustc_hir::{ForeignItemKind, ImplItemKind, ItemKind, Node, TraitItemKind}; - - debug!("environment(def_id = {:?})", def_id); - - // The environment of an impl Trait type is its defining function's environment. - if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) { - return well_formed_types_in_env(tcx, parent.to_def_id()); - } - - // Compute the bounds on `Self` and the type parameters. - let ty::InstantiatedPredicates { predicates, .. } = - tcx.predicates_of(def_id).instantiate_identity(tcx); - - let clauses = predicates.into_iter(); - - if !def_id.is_local() { - return ty::List::empty(); - } - let node = tcx.hir().get_by_def_id(def_id.expect_local()); - - enum NodeKind { - TraitImpl, - InherentImpl, - Fn, - Other, - } - - let node_kind = match node { - Node::TraitItem(item) => match item.kind { - TraitItemKind::Fn(..) => NodeKind::Fn, - _ => NodeKind::Other, - }, - - Node::ImplItem(item) => match item.kind { - ImplItemKind::Fn(..) => NodeKind::Fn, - _ => NodeKind::Other, - }, - - Node::Item(item) => match item.kind { - ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => NodeKind::TraitImpl, - ItemKind::Impl(hir::Impl { of_trait: None, .. }) => NodeKind::InherentImpl, - ItemKind::Fn(..) => NodeKind::Fn, - _ => NodeKind::Other, - }, - - Node::ForeignItem(item) => match item.kind { - ForeignItemKind::Fn(..) => NodeKind::Fn, - _ => NodeKind::Other, - }, - - // FIXME: closures? - _ => NodeKind::Other, - }; - - // FIXME(eddyb) isn't the unordered nature of this a hazard? - let mut inputs = FxIndexSet::default(); - - match node_kind { - // In a trait impl, we assume that the header trait ref and all its - // constituents are well-formed. - NodeKind::TraitImpl => { - let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl").subst_identity(); - - // FIXME(chalk): this has problems because of late-bound regions - //inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk())); - inputs.extend(trait_ref.substs.iter()); - } - - // In an inherent impl, we assume that the receiver type and all its - // constituents are well-formed. - NodeKind::InherentImpl => { - let self_ty = tcx.type_of(def_id).subst_identity(); - inputs.extend(self_ty.walk()); - } - - // In an fn, we assume that the arguments and all their constituents are - // well-formed. - NodeKind::Fn => { - let fn_sig = tcx.fn_sig(def_id).subst_identity(); - let fn_sig = tcx.liberate_late_bound_regions(def_id, fn_sig); - - inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk())); - } - - NodeKind::Other => (), - } - let input_clauses = inputs.into_iter().filter_map(|arg| { - match arg.unpack() { - ty::GenericArgKind::Type(ty) => { - Some(ty::ClauseKind::TypeWellFormedFromEnv(ty).to_predicate(tcx)) - } - - // FIXME(eddyb) no WF conditions from lifetimes? - ty::GenericArgKind::Lifetime(_) => None, - - // FIXME(eddyb) support const generics in Chalk - ty::GenericArgKind::Const(_) => None, - } - }); - - tcx.mk_clauses_from_iter(clauses.chain(input_clauses)) -} - fn param_env_reveal_all_normalized(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { tcx.param_env(def_id).with_reveal_all_normalized(tcx) } diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index ae16fbb162e..878a6b784ed 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -57,11 +57,19 @@ pub trait Interner: Sized { type ParamTy: Clone + Debug + Hash + Ord; type BoundTy: Clone + Debug + Hash + Ord; type PlaceholderType: Clone + Debug + Hash + Ord; - type InferTy: Clone + Debug + Hash + Ord; type ErrorGuaranteed: Clone + Debug + Hash + Ord; type PredicateKind: Clone + Debug + Hash + PartialEq + Eq; type AllocId: Clone + Debug + Hash + Ord; + type InferConst: Clone + Debug + Hash + Ord; + type AliasConst: Clone + Debug + Hash + Ord; + type PlaceholderConst: Clone + Debug + Hash + Ord; + type ParamConst: Clone + Debug + Hash + Ord; + type BoundConst: Clone + Debug + Hash + Ord; + type InferTy: Clone + Debug + Hash + Ord; + type ValueConst: Clone + Debug + Hash + Ord; + type ExprConst: Clone + Debug + Hash + Ord; + type EarlyBoundRegion: Clone + Debug + Hash + Ord; type BoundRegion: Clone + Debug + Hash + Ord; type FreeRegion: Clone + Debug + Hash + Ord; diff --git a/compiler/rustc_type_ir/src/structural_impls.rs b/compiler/rustc_type_ir/src/structural_impls.rs index 553d7f31b2d..1e42175f6e3 100644 --- a/compiler/rustc_type_ir/src/structural_impls.rs +++ b/compiler/rustc_type_ir/src/structural_impls.rs @@ -4,7 +4,7 @@ use crate::fold::{FallibleTypeFolder, TypeFoldable}; use crate::visit::{TypeVisitable, TypeVisitor}; -use crate::{FloatTy, IntTy, Interner, UintTy}; +use crate::{ConstKind, FloatTy, IntTy, Interner, UintTy}; use rustc_data_structures::functor::IdFunctor; use rustc_data_structures::sync::Lrc; use rustc_index::{Idx, IndexVec}; @@ -182,3 +182,21 @@ impl fmt::Debug for FloatTy { write!(f, "{}", self.name_str()) } } + +impl<I: Interner> fmt::Debug for ConstKind<I> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use ConstKind::*; + match self { + Param(param) => write!(f, "{param:?}"), + Infer(var) => write!(f, "{var:?}"), + Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var.clone()), + Placeholder(placeholder) => write!(f, "{placeholder:?}"), + Unevaluated(uv) => { + write!(f, "{uv:?}") + } + Value(valtree) => write!(f, "{valtree:?}"), + Error(_) => write!(f, "{{const error}}"), + Expr(expr) => write!(f, "{expr:?}"), + } + } +} diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index f621673f1d6..b696f9b9b59 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -876,6 +876,224 @@ where } } +/// Represents a constant in Rust. +// #[derive(derive_more::From)] +pub enum ConstKind<I: Interner> { + /// A const generic parameter. + Param(I::ParamConst), + + /// Infer the value of the const. + Infer(I::InferConst), + + /// Bound const variable, used only when preparing a trait query. + Bound(DebruijnIndex, I::BoundConst), + + /// A placeholder const - universally quantified higher-ranked const. + Placeholder(I::PlaceholderConst), + + /// An unnormalized const item such as an anon const or assoc const or free const item. + /// Right now anything other than anon consts does not actually work properly but this + /// should + Unevaluated(I::AliasConst), + + /// Used to hold computed value. + Value(I::ValueConst), + + /// A placeholder for a const which could not be computed; this is + /// propagated to avoid useless error messages. + Error(I::ErrorGuaranteed), + + /// Unevaluated non-const-item, used by `feature(generic_const_exprs)` to represent + /// const arguments such as `N + 1` or `foo(N)` + Expr(I::ExprConst), +} + +const fn const_kind_discriminant<I: Interner>(value: &ConstKind<I>) -> usize { + match value { + ConstKind::Param(_) => 0, + ConstKind::Infer(_) => 1, + ConstKind::Bound(_, _) => 2, + ConstKind::Placeholder(_) => 3, + ConstKind::Unevaluated(_) => 4, + ConstKind::Value(_) => 5, + ConstKind::Error(_) => 6, + ConstKind::Expr(_) => 7, + } +} + +impl<I: Interner> hash::Hash for ConstKind<I> { + fn hash<H: hash::Hasher>(&self, state: &mut H) { + const_kind_discriminant(self).hash(state); + match self { + ConstKind::Param(p) => p.hash(state), + ConstKind::Infer(i) => i.hash(state), + ConstKind::Bound(d, b) => { + d.hash(state); + b.hash(state); + } + ConstKind::Placeholder(p) => p.hash(state), + ConstKind::Unevaluated(u) => u.hash(state), + ConstKind::Value(v) => v.hash(state), + ConstKind::Error(e) => e.hash(state), + ConstKind::Expr(e) => e.hash(state), + } + } +} + +impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for ConstKind<I> +where + I::ParamConst: HashStable<CTX>, + I::InferConst: HashStable<CTX>, + I::BoundConst: HashStable<CTX>, + I::PlaceholderConst: HashStable<CTX>, + I::AliasConst: HashStable<CTX>, + I::ValueConst: HashStable<CTX>, + I::ErrorGuaranteed: HashStable<CTX>, + I::ExprConst: HashStable<CTX>, +{ + fn hash_stable( + &self, + hcx: &mut CTX, + hasher: &mut rustc_data_structures::stable_hasher::StableHasher, + ) { + const_kind_discriminant(self).hash_stable(hcx, hasher); + match self { + ConstKind::Param(p) => p.hash_stable(hcx, hasher), + ConstKind::Infer(i) => i.hash_stable(hcx, hasher), + ConstKind::Bound(d, b) => { + d.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher); + } + ConstKind::Placeholder(p) => p.hash_stable(hcx, hasher), + ConstKind::Unevaluated(u) => u.hash_stable(hcx, hasher), + ConstKind::Value(v) => v.hash_stable(hcx, hasher), + ConstKind::Error(e) => e.hash_stable(hcx, hasher), + ConstKind::Expr(e) => e.hash_stable(hcx, hasher), + } + } +} + +impl<I: Interner, D: TyDecoder<I = I>> Decodable<D> for ConstKind<I> +where + I::ParamConst: Decodable<D>, + I::InferConst: Decodable<D>, + I::BoundConst: Decodable<D>, + I::PlaceholderConst: Decodable<D>, + I::AliasConst: Decodable<D>, + I::ValueConst: Decodable<D>, + I::ErrorGuaranteed: Decodable<D>, + I::ExprConst: Decodable<D>, +{ + fn decode(d: &mut D) -> Self { + match Decoder::read_usize(d) { + 0 => ConstKind::Param(Decodable::decode(d)), + 1 => ConstKind::Infer(Decodable::decode(d)), + 2 => ConstKind::Bound(Decodable::decode(d), Decodable::decode(d)), + 3 => ConstKind::Placeholder(Decodable::decode(d)), + 4 => ConstKind::Unevaluated(Decodable::decode(d)), + 5 => ConstKind::Value(Decodable::decode(d)), + 6 => ConstKind::Error(Decodable::decode(d)), + 7 => ConstKind::Expr(Decodable::decode(d)), + _ => panic!( + "{}", + format!( + "invalid enum variant tag while decoding `{}`, expected 0..{}", + "ConstKind", 8, + ) + ), + } + } +} + +impl<I: Interner, E: TyEncoder<I = I>> Encodable<E> for ConstKind<I> +where + I::ParamConst: Encodable<E>, + I::InferConst: Encodable<E>, + I::BoundConst: Encodable<E>, + I::PlaceholderConst: Encodable<E>, + I::AliasConst: Encodable<E>, + I::ValueConst: Encodable<E>, + I::ErrorGuaranteed: Encodable<E>, + I::ExprConst: Encodable<E>, +{ + fn encode(&self, e: &mut E) { + let disc = const_kind_discriminant(self); + match self { + ConstKind::Param(p) => e.emit_enum_variant(disc, |e| p.encode(e)), + ConstKind::Infer(i) => e.emit_enum_variant(disc, |e| i.encode(e)), + ConstKind::Bound(d, b) => e.emit_enum_variant(disc, |e| { + d.encode(e); + b.encode(e); + }), + ConstKind::Placeholder(p) => e.emit_enum_variant(disc, |e| p.encode(e)), + ConstKind::Unevaluated(u) => e.emit_enum_variant(disc, |e| u.encode(e)), + ConstKind::Value(v) => e.emit_enum_variant(disc, |e| v.encode(e)), + ConstKind::Error(er) => e.emit_enum_variant(disc, |e| er.encode(e)), + ConstKind::Expr(ex) => e.emit_enum_variant(disc, |e| ex.encode(e)), + } + } +} + +impl<I: Interner> PartialOrd for ConstKind<I> { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +impl<I: Interner> Ord for ConstKind<I> { + fn cmp(&self, other: &Self) -> Ordering { + const_kind_discriminant(self) + .cmp(&const_kind_discriminant(other)) + .then_with(|| match (self, other) { + (ConstKind::Param(p1), ConstKind::Param(p2)) => p1.cmp(p2), + (ConstKind::Infer(i1), ConstKind::Infer(i2)) => i1.cmp(i2), + (ConstKind::Bound(d1, b1), ConstKind::Bound(d2, b2)) => d1.cmp(d2).then_with(|| b1.cmp(b2)), + (ConstKind::Placeholder(p1), ConstKind::Placeholder(p2)) => p1.cmp(p2), + (ConstKind::Unevaluated(u1), ConstKind::Unevaluated(u2)) => u1.cmp(u2), + (ConstKind::Value(v1), ConstKind::Value(v2)) => v1.cmp(v2), + (ConstKind::Error(e1), ConstKind::Error(e2)) => e1.cmp(e2), + (ConstKind::Expr(e1), ConstKind::Expr(e2)) => e1.cmp(e2), + _ => { + debug_assert!(false, "This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}"); + Ordering::Equal + } + }) + } +} + +impl<I: Interner> PartialEq for ConstKind<I> { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Param(l0), Self::Param(r0)) => l0 == r0, + (Self::Infer(l0), Self::Infer(r0)) => l0 == r0, + (Self::Bound(l0, l1), Self::Bound(r0, r1)) => l0 == r0 && l1 == r1, + (Self::Placeholder(l0), Self::Placeholder(r0)) => l0 == r0, + (Self::Unevaluated(l0), Self::Unevaluated(r0)) => l0 == r0, + (Self::Value(l0), Self::Value(r0)) => l0 == r0, + (Self::Error(l0), Self::Error(r0)) => l0 == r0, + (Self::Expr(l0), Self::Expr(r0)) => l0 == r0, + _ => false, + } + } +} + +impl<I: Interner> Eq for ConstKind<I> {} + +impl<I: Interner> Clone for ConstKind<I> { + fn clone(&self) -> Self { + match self { + Self::Param(arg0) => Self::Param(arg0.clone()), + Self::Infer(arg0) => Self::Infer(arg0.clone()), + Self::Bound(arg0, arg1) => Self::Bound(arg0.clone(), arg1.clone()), + Self::Placeholder(arg0) => Self::Placeholder(arg0.clone()), + Self::Unevaluated(arg0) => Self::Unevaluated(arg0.clone()), + Self::Value(arg0) => Self::Value(arg0.clone()), + Self::Error(arg0) => Self::Error(arg0.clone()), + Self::Expr(arg0) => Self::Expr(arg0.clone()), + } + } +} + /// Representation of regions. Note that the NLL checker uses a distinct /// representation of regions. For this reason, it internally replaces all the /// regions with inference variables -- the index of the variable is then used diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index fa23367593d..8ef2bac9282 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1319,56 +1319,39 @@ impl Clone for Box<str> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T, A1, A2> PartialEq<Box<T, A2>> for Box<T, A1> -where - T: ?Sized + PartialEq, - A1: Allocator, - A2: Allocator, -{ +impl<T: ?Sized + PartialEq, A: Allocator> PartialEq for Box<T, A> { #[inline] - fn eq(&self, other: &Box<T, A2>) -> bool { + fn eq(&self, other: &Self) -> bool { PartialEq::eq(&**self, &**other) } - #[inline] - fn ne(&self, other: &Box<T, A2>) -> bool { + fn ne(&self, other: &Self) -> bool { PartialEq::ne(&**self, &**other) } } - #[stable(feature = "rust1", since = "1.0.0")] -impl<T, A1, A2> PartialOrd<Box<T, A2>> for Box<T, A1> -where - T: ?Sized + PartialOrd, - A1: Allocator, - A2: Allocator, -{ +impl<T: ?Sized + PartialOrd, A: Allocator> PartialOrd for Box<T, A> { #[inline] - fn partial_cmp(&self, other: &Box<T, A2>) -> Option<Ordering> { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { PartialOrd::partial_cmp(&**self, &**other) } - #[inline] - fn lt(&self, other: &Box<T, A2>) -> bool { + fn lt(&self, other: &Self) -> bool { PartialOrd::lt(&**self, &**other) } - #[inline] - fn le(&self, other: &Box<T, A2>) -> bool { + fn le(&self, other: &Self) -> bool { PartialOrd::le(&**self, &**other) } - #[inline] - fn ge(&self, other: &Box<T, A2>) -> bool { + fn ge(&self, other: &Self) -> bool { PartialOrd::ge(&**self, &**other) } - #[inline] - fn gt(&self, other: &Box<T, A2>) -> bool { + fn gt(&self, other: &Self) -> bool { PartialOrd::gt(&**self, &**other) } } - #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized + Ord, A: Allocator> Ord for Box<T, A> { #[inline] diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 21824c8a17c..ddd93e9a436 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1906,6 +1906,7 @@ fn test_stable_pointers() { assert_eq!(*v0, 13); // Smoke test that would fire even outside Miri if an actual relocation happened. + // Also ensures the pointer is still writeable after all this. *v0 -= 13; assert_eq!(v[0], 0); } diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 7437722fd06..0488c807604 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -132,7 +132,12 @@ mod c_char_definition { ), all( target_os = "netbsd", - any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc") + any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "riscv64" + ) ), all( target_os = "vxworks", diff --git a/library/core/tests/future.rs b/library/core/tests/future.rs index 74b6f74e401..db417256dd0 100644 --- a/library/core/tests/future.rs +++ b/library/core/tests/future.rs @@ -30,7 +30,6 @@ fn poll_n(val: usize, num: usize) -> PollN { } #[test] -#[cfg_attr(miri, ignore)] // self-referential generators do not work with Miri's aliasing checks fn test_join() { block_on(async move { let x = join!(async { 0 }).await; diff --git a/library/portable-simd/.github/workflows/ci.yml b/library/portable-simd/.github/workflows/ci.yml index acd47a3da72..1ff377fce34 100644 --- a/library/portable-simd/.github/workflows/ci.yml +++ b/library/portable-simd/.github/workflows/ci.yml @@ -38,8 +38,9 @@ jobs: - i586-unknown-linux-gnu - aarch64-unknown-linux-gnu - armv7-unknown-linux-gnueabihf - - mips-unknown-linux-gnu - - mips64-unknown-linux-gnuabi64 + # non-nightly since https://github.com/rust-lang/rust/pull/113274 + # - mips-unknown-linux-gnu + # - mips64-unknown-linux-gnuabi64 - powerpc-unknown-linux-gnu - powerpc64-unknown-linux-gnu - riscv64gc-unknown-linux-gnu @@ -191,8 +192,8 @@ jobs: # Note: The issue above means neither of these mips targets will use # MSA (mips simd) but MIPS uses a nonstandard binary representation # for NaNs which makes it worth testing on despite that. - - mips-unknown-linux-gnu - - mips64-unknown-linux-gnuabi64 + # - mips-unknown-linux-gnu + # - mips64-unknown-linux-gnuabi64 - riscv64gc-unknown-linux-gnu # TODO this test works, but it appears to time out # - powerpc-unknown-linux-gnu diff --git a/library/portable-simd/crates/core_simd/src/cast.rs b/library/portable-simd/crates/core_simd/src/cast.rs index 65a3f845ffc..1c3592f8075 100644 --- a/library/portable-simd/crates/core_simd/src/cast.rs +++ b/library/portable-simd/crates/core_simd/src/cast.rs @@ -1,55 +1,51 @@ use crate::simd::SimdElement; +mod sealed { + /// Cast vector elements to other types. + /// + /// # Safety + /// Implementing this trait asserts that the type is a valid vector element for the `simd_cast` + /// or `simd_as` intrinsics. + pub unsafe trait Sealed {} +} +use sealed::Sealed; + /// Supporting trait for `Simd::cast`. Typically doesn't need to be used directly. -/// -/// # Safety -/// Implementing this trait asserts that the type is a valid vector element for the `simd_cast` or -/// `simd_as` intrinsics. -pub unsafe trait SimdCast: SimdElement {} +pub trait SimdCast: Sealed + SimdElement {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for i8 {} +unsafe impl Sealed for i8 {} +impl SimdCast for i8 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for i16 {} +unsafe impl Sealed for i16 {} +impl SimdCast for i16 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for i32 {} +unsafe impl Sealed for i32 {} +impl SimdCast for i32 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for i64 {} +unsafe impl Sealed for i64 {} +impl SimdCast for i64 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for isize {} +unsafe impl Sealed for isize {} +impl SimdCast for isize {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for u8 {} +unsafe impl Sealed for u8 {} +impl SimdCast for u8 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for u16 {} +unsafe impl Sealed for u16 {} +impl SimdCast for u16 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for u32 {} +unsafe impl Sealed for u32 {} +impl SimdCast for u32 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for u64 {} +unsafe impl Sealed for u64 {} +impl SimdCast for u64 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for usize {} +unsafe impl Sealed for usize {} +impl SimdCast for usize {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for f32 {} +unsafe impl Sealed for f32 {} +impl SimdCast for f32 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for f64 {} - -/// Supporting trait for `Simd::cast_ptr`. Typically doesn't need to be used directly. -/// -/// # Safety -/// Implementing this trait asserts that the type is a valid vector element for the `simd_cast_ptr` -/// intrinsic. -pub unsafe trait SimdCastPtr<T> {} - -// Safety: pointers can be cast to other pointer types -unsafe impl<T, U> SimdCastPtr<T> for *const U -where - U: core::ptr::Pointee, - T: core::ptr::Pointee<Metadata = U::Metadata>, -{ -} -// Safety: pointers can be cast to other pointer types -unsafe impl<T, U> SimdCastPtr<T> for *mut U -where - U: core::ptr::Pointee, - T: core::ptr::Pointee<Metadata = U::Metadata>, -{ -} +unsafe impl Sealed for f64 {} +impl SimdCast for f64 {} diff --git a/library/portable-simd/crates/core_simd/src/elements/const_ptr.rs b/library/portable-simd/crates/core_simd/src/elements/const_ptr.rs index 0ef9802b5e2..f215f9a61d0 100644 --- a/library/portable-simd/crates/core_simd/src/elements/const_ptr.rs +++ b/library/portable-simd/crates/core_simd/src/elements/const_ptr.rs @@ -1,5 +1,5 @@ use super::sealed::Sealed; -use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount}; +use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SimdUint, SupportedLaneCount}; /// Operations on SIMD vectors of constant pointers. pub trait SimdConstPtr: Copy + Sealed { @@ -9,6 +9,9 @@ pub trait SimdConstPtr: Copy + Sealed { /// Vector of `isize` with the same number of lanes. type Isize; + /// Vector of const pointers with the same number of lanes. + type CastPtr<T>; + /// Vector of mutable pointers to the same type. type MutPtr; @@ -18,6 +21,11 @@ pub trait SimdConstPtr: Copy + Sealed { /// Returns `true` for each lane that is null. fn is_null(self) -> Self::Mask; + /// Casts to a pointer of another type. + /// + /// Equivalent to calling [`pointer::cast`] on each lane. + fn cast<T>(self) -> Self::CastPtr<T>; + /// Changes constness without changing the type. /// /// Equivalent to calling [`pointer::cast_mut`] on each lane. @@ -78,6 +86,7 @@ where { type Usize = Simd<usize, LANES>; type Isize = Simd<isize, LANES>; + type CastPtr<U> = Simd<*const U, LANES>; type MutPtr = Simd<*mut T, LANES>; type Mask = Mask<isize, LANES>; @@ -87,8 +96,21 @@ where } #[inline] + fn cast<U>(self) -> Self::CastPtr<U> { + // SimdElement currently requires zero-sized metadata, so this should never fail. + // If this ever changes, `simd_cast_ptr` should produce a post-mono error. + use core::{mem::size_of, ptr::Pointee}; + assert_eq!(size_of::<<T as Pointee>::Metadata>(), 0); + assert_eq!(size_of::<<U as Pointee>::Metadata>(), 0); + + // Safety: pointers can be cast + unsafe { intrinsics::simd_cast_ptr(self) } + } + + #[inline] fn cast_mut(self) -> Self::MutPtr { - self.cast_ptr() + // Safety: pointers can be cast + unsafe { intrinsics::simd_cast_ptr(self) } } #[inline] @@ -106,9 +128,9 @@ where // In the mean-time, this operation is defined to be "as if" it was // a wrapping_offset, so we can emulate it as such. This should properly // restore pointer provenance even under today's compiler. - self.cast_ptr::<*const u8>() + self.cast::<u8>() .wrapping_offset(addr.cast::<isize>() - self.addr().cast::<isize>()) - .cast_ptr() + .cast() } #[inline] diff --git a/library/portable-simd/crates/core_simd/src/elements/float.rs b/library/portable-simd/crates/core_simd/src/elements/float.rs index d6022327055..501c1c5ddd3 100644 --- a/library/portable-simd/crates/core_simd/src/elements/float.rs +++ b/library/portable-simd/crates/core_simd/src/elements/float.rs @@ -1,6 +1,6 @@ use super::sealed::Sealed; use crate::simd::{ - intrinsics, LaneCount, Mask, Simd, SimdElement, SimdPartialEq, SimdPartialOrd, + intrinsics, LaneCount, Mask, Simd, SimdCast, SimdElement, SimdPartialEq, SimdPartialOrd, SupportedLaneCount, }; @@ -15,6 +15,53 @@ pub trait SimdFloat: Copy + Sealed { /// Bit representation of this SIMD vector type. type Bits; + /// A SIMD vector with a different element type. + type Cast<T: SimdElement>; + + /// Performs elementwise conversion of this vector's elements to another SIMD-valid type. + /// + /// This follows the semantics of Rust's `as` conversion for floats (truncating or saturating + /// at the limits) for each element. + /// + /// # Example + /// ``` + /// # #![feature(portable_simd)] + /// # #[cfg(feature = "as_crate")] use core_simd::simd; + /// # #[cfg(not(feature = "as_crate"))] use core::simd; + /// # use simd::{SimdFloat, SimdInt, Simd}; + /// let floats: Simd<f32, 4> = Simd::from_array([1.9, -4.5, f32::INFINITY, f32::NAN]); + /// let ints = floats.cast::<i32>(); + /// assert_eq!(ints, Simd::from_array([1, -4, i32::MAX, 0])); + /// + /// // Formally equivalent, but `Simd::cast` can optimize better. + /// assert_eq!(ints, Simd::from_array(floats.to_array().map(|x| x as i32))); + /// + /// // The float conversion does not round-trip. + /// let floats_again = ints.cast(); + /// assert_ne!(floats, floats_again); + /// assert_eq!(floats_again, Simd::from_array([1.0, -4.0, 2147483647.0, 0.0])); + /// ``` + #[must_use] + fn cast<T: SimdCast>(self) -> Self::Cast<T>; + + /// Rounds toward zero and converts to the same-width integer type, assuming that + /// the value is finite and fits in that type. + /// + /// # Safety + /// The value must: + /// + /// * Not be NaN + /// * Not be infinite + /// * Be representable in the return type, after truncating off its fractional part + /// + /// If these requirements are infeasible or costly, consider using the safe function [cast], + /// which saturates on conversion. + /// + /// [cast]: Simd::cast + unsafe fn to_int_unchecked<I: SimdCast>(self) -> Self::Cast<I> + where + Self::Scalar: core::convert::FloatToInt<I>; + /// Raw transmutation to an unsigned integer vector type with the /// same size and number of lanes. #[must_use = "method returns a new vector and does not mutate the original value"] @@ -206,6 +253,24 @@ macro_rules! impl_trait { type Mask = Mask<<$mask_ty as SimdElement>::Mask, LANES>; type Scalar = $ty; type Bits = Simd<$bits_ty, LANES>; + type Cast<T: SimdElement> = Simd<T, LANES>; + + #[inline] + fn cast<T: SimdCast>(self) -> Self::Cast<T> + { + // Safety: supported types are guaranteed by SimdCast + unsafe { intrinsics::simd_as(self) } + } + + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + unsafe fn to_int_unchecked<I: SimdCast>(self) -> Self::Cast<I> + where + Self::Scalar: core::convert::FloatToInt<I>, + { + // Safety: supported types are guaranteed by SimdCast, the caller is responsible for the extra invariants + unsafe { intrinsics::simd_cast(self) } + } #[inline] fn to_bits(self) -> Simd<$bits_ty, LANES> { diff --git a/library/portable-simd/crates/core_simd/src/elements/int.rs b/library/portable-simd/crates/core_simd/src/elements/int.rs index 9b8c37ed466..6db89ff9a65 100644 --- a/library/portable-simd/crates/core_simd/src/elements/int.rs +++ b/library/portable-simd/crates/core_simd/src/elements/int.rs @@ -1,6 +1,6 @@ use super::sealed::Sealed; use crate::simd::{ - intrinsics, LaneCount, Mask, Simd, SimdElement, SimdPartialOrd, SupportedLaneCount, + intrinsics, LaneCount, Mask, Simd, SimdCast, SimdElement, SimdPartialOrd, SupportedLaneCount, }; /// Operations on SIMD vectors of signed integers. @@ -11,6 +11,16 @@ pub trait SimdInt: Copy + Sealed { /// Scalar type contained by this SIMD vector type. type Scalar; + /// A SIMD vector with a different element type. + type Cast<T: SimdElement>; + + /// Performs elementwise conversion of this vector's elements to another SIMD-valid type. + /// + /// This follows the semantics of Rust's `as` conversion for casting integers (wrapping to + /// other integer types, and saturating to float types). + #[must_use] + fn cast<T: SimdCast>(self) -> Self::Cast<T>; + /// Lanewise saturating add. /// /// # Examples @@ -198,6 +208,13 @@ macro_rules! impl_trait { { type Mask = Mask<<$ty as SimdElement>::Mask, LANES>; type Scalar = $ty; + type Cast<T: SimdElement> = Simd<T, LANES>; + + #[inline] + fn cast<T: SimdCast>(self) -> Self::Cast<T> { + // Safety: supported types are guaranteed by SimdCast + unsafe { intrinsics::simd_as(self) } + } #[inline] fn saturating_add(self, second: Self) -> Self { diff --git a/library/portable-simd/crates/core_simd/src/elements/mut_ptr.rs b/library/portable-simd/crates/core_simd/src/elements/mut_ptr.rs index d87986b4a09..4bdc6a14ce4 100644 --- a/library/portable-simd/crates/core_simd/src/elements/mut_ptr.rs +++ b/library/portable-simd/crates/core_simd/src/elements/mut_ptr.rs @@ -1,5 +1,5 @@ use super::sealed::Sealed; -use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount}; +use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SimdUint, SupportedLaneCount}; /// Operations on SIMD vectors of mutable pointers. pub trait SimdMutPtr: Copy + Sealed { @@ -9,6 +9,9 @@ pub trait SimdMutPtr: Copy + Sealed { /// Vector of `isize` with the same number of lanes. type Isize; + /// Vector of const pointers with the same number of lanes. + type CastPtr<T>; + /// Vector of constant pointers to the same type. type ConstPtr; @@ -18,6 +21,11 @@ pub trait SimdMutPtr: Copy + Sealed { /// Returns `true` for each lane that is null. fn is_null(self) -> Self::Mask; + /// Casts to a pointer of another type. + /// + /// Equivalent to calling [`pointer::cast`] on each lane. + fn cast<T>(self) -> Self::CastPtr<T>; + /// Changes constness without changing the type. /// /// Equivalent to calling [`pointer::cast_const`] on each lane. @@ -73,6 +81,7 @@ where { type Usize = Simd<usize, LANES>; type Isize = Simd<isize, LANES>; + type CastPtr<U> = Simd<*mut U, LANES>; type ConstPtr = Simd<*const T, LANES>; type Mask = Mask<isize, LANES>; @@ -82,8 +91,21 @@ where } #[inline] + fn cast<U>(self) -> Self::CastPtr<U> { + // SimdElement currently requires zero-sized metadata, so this should never fail. + // If this ever changes, `simd_cast_ptr` should produce a post-mono error. + use core::{mem::size_of, ptr::Pointee}; + assert_eq!(size_of::<<T as Pointee>::Metadata>(), 0); + assert_eq!(size_of::<<U as Pointee>::Metadata>(), 0); + + // Safety: pointers can be cast + unsafe { intrinsics::simd_cast_ptr(self) } + } + + #[inline] fn cast_const(self) -> Self::ConstPtr { - self.cast_ptr() + // Safety: pointers can be cast + unsafe { intrinsics::simd_cast_ptr(self) } } #[inline] @@ -101,9 +123,9 @@ where // In the mean-time, this operation is defined to be "as if" it was // a wrapping_offset, so we can emulate it as such. This should properly // restore pointer provenance even under today's compiler. - self.cast_ptr::<*mut u8>() + self.cast::<u8>() .wrapping_offset(addr.cast::<isize>() - self.addr().cast::<isize>()) - .cast_ptr() + .cast() } #[inline] diff --git a/library/portable-simd/crates/core_simd/src/elements/uint.rs b/library/portable-simd/crates/core_simd/src/elements/uint.rs index 21e7e76eb3d..3926c395ec9 100644 --- a/library/portable-simd/crates/core_simd/src/elements/uint.rs +++ b/library/portable-simd/crates/core_simd/src/elements/uint.rs @@ -1,11 +1,21 @@ use super::sealed::Sealed; -use crate::simd::{intrinsics, LaneCount, Simd, SupportedLaneCount}; +use crate::simd::{intrinsics, LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount}; /// Operations on SIMD vectors of unsigned integers. pub trait SimdUint: Copy + Sealed { /// Scalar type contained by this SIMD vector type. type Scalar; + /// A SIMD vector with a different element type. + type Cast<T: SimdElement>; + + /// Performs elementwise conversion of this vector's elements to another SIMD-valid type. + /// + /// This follows the semantics of Rust's `as` conversion for casting integers (wrapping to + /// other integer types, and saturating to float types). + #[must_use] + fn cast<T: SimdCast>(self) -> Self::Cast<T>; + /// Lanewise saturating add. /// /// # Examples @@ -77,6 +87,13 @@ macro_rules! impl_trait { LaneCount<LANES>: SupportedLaneCount, { type Scalar = $ty; + type Cast<T: SimdElement> = Simd<T, LANES>; + + #[inline] + fn cast<T: SimdCast>(self) -> Self::Cast<T> { + // Safety: supported types are guaranteed by SimdCast + unsafe { intrinsics::simd_as(self) } + } #[inline] fn saturating_add(self, second: Self) -> Self { diff --git a/library/portable-simd/crates/core_simd/src/iter.rs b/library/portable-simd/crates/core_simd/src/iter.rs index 3275b4db8e4..328c995b81d 100644 --- a/library/portable-simd/crates/core_simd/src/iter.rs +++ b/library/portable-simd/crates/core_simd/src/iter.rs @@ -10,6 +10,7 @@ macro_rules! impl_traits { where LaneCount<LANES>: SupportedLaneCount, { + #[inline] fn sum<I: Iterator<Item = Self>>(iter: I) -> Self { iter.fold(Simd::splat(0 as $type), Add::add) } @@ -19,6 +20,7 @@ macro_rules! impl_traits { where LaneCount<LANES>: SupportedLaneCount, { + #[inline] fn product<I: Iterator<Item = Self>>(iter: I) -> Self { iter.fold(Simd::splat(1 as $type), Mul::mul) } @@ -28,6 +30,7 @@ macro_rules! impl_traits { where LaneCount<LANES>: SupportedLaneCount, { + #[inline] fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self { iter.fold(Simd::splat(0 as $type), Add::add) } @@ -37,6 +40,7 @@ macro_rules! impl_traits { where LaneCount<LANES>: SupportedLaneCount, { + #[inline] fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self { iter.fold(Simd::splat(1 as $type), Mul::mul) } diff --git a/library/portable-simd/crates/core_simd/src/lib.rs b/library/portable-simd/crates/core_simd/src/lib.rs index e5307de2155..fde406bda70 100644 --- a/library/portable-simd/crates/core_simd/src/lib.rs +++ b/library/portable-simd/crates/core_simd/src/lib.rs @@ -16,7 +16,7 @@ )] #![cfg_attr(feature = "generic_const_exprs", feature(generic_const_exprs))] #![cfg_attr(feature = "generic_const_exprs", allow(incomplete_features))] -#![warn(missing_docs)] +#![warn(missing_docs, clippy::missing_inline_in_public_items)] // basically all items, really #![deny(unsafe_op_in_unsafe_fn, clippy::undocumented_unsafe_blocks)] #![unstable(feature = "portable_simd", issue = "86656")] //! Portable SIMD module. diff --git a/library/portable-simd/crates/core_simd/src/masks.rs b/library/portable-simd/crates/core_simd/src/masks.rs index e0f3c7beef6..fea687bdc1a 100644 --- a/library/portable-simd/crates/core_simd/src/masks.rs +++ b/library/portable-simd/crates/core_simd/src/masks.rs @@ -179,6 +179,7 @@ where /// Panics if any lane is not 0 or -1. #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] + #[track_caller] pub fn from_int(value: Simd<T, LANES>) -> Self { assert!(T::valid(value), "all values must be either 0 or -1",); // Safety: the validity has been checked @@ -217,6 +218,7 @@ where /// Panics if `lane` is greater than or equal to the number of lanes in the vector. #[inline] #[must_use = "method returns a new bool and does not mutate the original value"] + #[track_caller] pub fn test(&self, lane: usize) -> bool { assert!(lane < LANES, "lane index out of range"); // Safety: the lane index has been checked @@ -240,6 +242,7 @@ where /// # Panics /// Panics if `lane` is greater than or equal to the number of lanes in the vector. #[inline] + #[track_caller] pub fn set(&mut self, lane: usize, value: bool) { assert!(lane < LANES, "lane index out of range"); // Safety: the lane index has been checked @@ -327,6 +330,7 @@ where T: MaskElement + fmt::Debug, LaneCount<LANES>: SupportedLaneCount, { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list() .entries((0..LANES).map(|lane| self.test(lane))) diff --git a/library/portable-simd/crates/core_simd/src/mod.rs b/library/portable-simd/crates/core_simd/src/mod.rs index 35c659b7a42..f9891a3b7c1 100644 --- a/library/portable-simd/crates/core_simd/src/mod.rs +++ b/library/portable-simd/crates/core_simd/src/mod.rs @@ -23,6 +23,8 @@ mod vendor; #[doc = include_str!("core_simd_docs.md")] pub mod simd { + pub mod prelude; + pub(crate) use crate::core_simd::intrinsics; pub use crate::core_simd::alias::*; diff --git a/library/portable-simd/crates/core_simd/src/ops.rs b/library/portable-simd/crates/core_simd/src/ops.rs index fc1e0bc426d..b007456cf2c 100644 --- a/library/portable-simd/crates/core_simd/src/ops.rs +++ b/library/portable-simd/crates/core_simd/src/ops.rs @@ -15,6 +15,7 @@ where I: core::slice::SliceIndex<[T]>, { type Output = I::Output; + #[inline] fn index(&self, index: I) -> &Self::Output { &self.as_array()[index] } @@ -26,6 +27,7 @@ where LaneCount<LANES>: SupportedLaneCount, I: core::slice::SliceIndex<[T]>, { + #[inline] fn index_mut(&mut self, index: I) -> &mut Self::Output { &mut self.as_mut_array()[index] } @@ -118,10 +120,14 @@ macro_rules! for_base_types { #[inline] #[must_use = "operator returns a new vector without mutating the inputs"] + // TODO: only useful for int Div::div, but we hope that this + // will essentially always always get inlined anyway. + #[track_caller] fn $call(self, rhs: Self) -> Self::Output { $macro_impl!(self, rhs, $inner, $scalar) } - })* + } + )* } } diff --git a/library/portable-simd/crates/core_simd/src/ord.rs b/library/portable-simd/crates/core_simd/src/ord.rs index 1ae9cd061fb..b2455190e82 100644 --- a/library/portable-simd/crates/core_simd/src/ord.rs +++ b/library/portable-simd/crates/core_simd/src/ord.rs @@ -94,6 +94,7 @@ macro_rules! impl_integer { } #[inline] + #[track_caller] fn simd_clamp(self, min: Self, max: Self) -> Self { assert!( min.simd_le(max).all(), @@ -200,6 +201,7 @@ macro_rules! impl_mask { } #[inline] + #[track_caller] fn simd_clamp(self, min: Self, max: Self) -> Self { assert!( min.simd_le(max).all(), @@ -254,6 +256,7 @@ where } #[inline] + #[track_caller] fn simd_clamp(self, min: Self, max: Self) -> Self { assert!( min.simd_le(max).all(), @@ -303,6 +306,7 @@ where } #[inline] + #[track_caller] fn simd_clamp(self, min: Self, max: Self) -> Self { assert!( min.simd_le(max).all(), diff --git a/library/portable-simd/crates/core_simd/src/simd/prelude.rs b/library/portable-simd/crates/core_simd/src/simd/prelude.rs new file mode 100644 index 00000000000..e8fdc932d49 --- /dev/null +++ b/library/portable-simd/crates/core_simd/src/simd/prelude.rs @@ -0,0 +1,80 @@ +//! The portable SIMD prelude. +//! +//! Includes important traits and types to be imported with a glob: +//! ```ignore +//! use std::simd::prelude::*; +//! ``` + +#[doc(no_inline)] +pub use super::{ + simd_swizzle, Mask, Simd, SimdConstPtr, SimdFloat, SimdInt, SimdMutPtr, SimdOrd, SimdPartialEq, + SimdPartialOrd, SimdUint, +}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{f32x1, f32x2, f32x4, f32x8, f32x16, f32x32, f32x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{f64x1, f64x2, f64x4, f64x8, f64x16, f64x32, f64x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{i8x1, i8x2, i8x4, i8x8, i8x16, i8x32, i8x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{i16x1, i16x2, i16x4, i16x8, i16x16, i16x32, i16x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{i32x1, i32x2, i32x4, i32x8, i32x16, i32x32, i32x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{i64x1, i64x2, i64x4, i64x8, i64x16, i64x32, i64x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{isizex1, isizex2, isizex4, isizex8, isizex16, isizex32, isizex64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{u8x1, u8x2, u8x4, u8x8, u8x16, u8x32, u8x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{u16x1, u16x2, u16x4, u16x8, u16x16, u16x32, u16x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{u32x1, u32x2, u32x4, u32x8, u32x16, u32x32, u32x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{u64x1, u64x2, u64x4, u64x8, u64x16, u64x32, u64x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{usizex1, usizex2, usizex4, usizex8, usizex16, usizex32, usizex64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{mask8x1, mask8x2, mask8x4, mask8x8, mask8x16, mask8x32, mask8x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{mask16x1, mask16x2, mask16x4, mask16x8, mask16x16, mask16x32, mask16x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{mask32x1, mask32x2, mask32x4, mask32x8, mask32x16, mask32x32, mask32x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{mask64x1, mask64x2, mask64x4, mask64x8, mask64x16, mask64x32, mask64x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{masksizex1, masksizex2, masksizex4, masksizex8, masksizex16, masksizex32, masksizex64}; diff --git a/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs b/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs index 6065d645937..ce621792534 100644 --- a/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs +++ b/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs @@ -16,9 +16,14 @@ where #[inline] pub fn swizzle_dyn(self, idxs: Simd<u8, N>) -> Self { #![allow(unused_imports, unused_unsafe)] - #[cfg(target_arch = "aarch64")] + #[cfg(all(target_arch = "aarch64", target_endian = "little"))] use core::arch::aarch64::{uint8x8_t, vqtbl1q_u8, vtbl1_u8}; - #[cfg(all(target_arch = "arm", target_feature = "v7", target_feature = "neon"))] + #[cfg(all( + target_arch = "arm", + target_feature = "v7", + target_feature = "neon", + target_endian = "little" + ))] use core::arch::arm::{uint8x8_t, vtbl1_u8}; #[cfg(target_arch = "wasm32")] use core::arch::wasm32 as wasm; @@ -29,13 +34,24 @@ where // SAFETY: Intrinsics covered by cfg unsafe { match N { - #[cfg(target_feature = "neon")] + #[cfg(all( + any( + target_arch = "aarch64", + all(target_arch = "arm", target_feature = "v7") + ), + target_feature = "neon", + target_endian = "little" + ))] 8 => transize(vtbl1_u8, self, idxs), #[cfg(target_feature = "ssse3")] 16 => transize(x86::_mm_shuffle_epi8, self, idxs), #[cfg(target_feature = "simd128")] 16 => transize(wasm::i8x16_swizzle, self, idxs), - #[cfg(all(target_arch = "aarch64", target_feature = "neon"))] + #[cfg(all( + target_arch = "aarch64", + target_feature = "neon", + target_endian = "little" + ))] 16 => transize(vqtbl1q_u8, self, idxs), #[cfg(all(target_feature = "avx2", not(target_feature = "avx512vbmi")))] 32 => transize_raw(avx2_pshufb, self, idxs), diff --git a/library/portable-simd/crates/core_simd/src/vector.rs b/library/portable-simd/crates/core_simd/src/vector.rs index 3809cc96151..9aa7bacfce9 100644 --- a/library/portable-simd/crates/core_simd/src/vector.rs +++ b/library/portable-simd/crates/core_simd/src/vector.rs @@ -1,6 +1,6 @@ use crate::simd::{ - intrinsics, LaneCount, Mask, MaskElement, SimdCast, SimdCastPtr, SimdConstPtr, SimdMutPtr, - SimdPartialOrd, SupportedLaneCount, Swizzle, + intrinsics, LaneCount, Mask, MaskElement, SimdConstPtr, SimdMutPtr, SimdPartialOrd, + SupportedLaneCount, Swizzle, }; use core::convert::{TryFrom, TryInto}; @@ -122,6 +122,7 @@ where /// let v = u32x4::splat(0); /// assert_eq!(v.lanes(), 4); /// ``` + #[inline] pub const fn lanes(&self) -> usize { Self::LANES } @@ -136,6 +137,7 @@ where /// let v = u32x4::splat(8); /// assert_eq!(v.as_array(), &[8, 8, 8, 8]); /// ``` + #[inline] pub fn splat(value: T) -> Self { // This is preferred over `[value; N]`, since it's explicitly a splat: // https://github.com/rust-lang/rust/issues/97804 @@ -156,6 +158,7 @@ where /// let v: u64x4 = Simd::from_array([0, 1, 2, 3]); /// assert_eq!(v.as_array(), &[0, 1, 2, 3]); /// ``` + #[inline] pub const fn as_array(&self) -> &[T; N] { // SAFETY: `Simd<T, N>` is just an overaligned `[T; N]` with // potential padding at the end, so pointer casting to a @@ -167,6 +170,7 @@ where } /// Returns a mutable array reference containing the entire SIMD vector. + #[inline] pub fn as_mut_array(&mut self) -> &mut [T; N] { // SAFETY: `Simd<T, N>` is just an overaligned `[T; N]` with // potential padding at the end, so pointer casting to a @@ -184,6 +188,7 @@ where /// /// # Safety /// Reading `ptr` must be safe, as if by `<*const [T; N]>::read_unaligned`. + #[inline] const unsafe fn load(ptr: *const [T; N]) -> Self { // There are potentially simpler ways to write this function, but this should result in // LLVM `load <N x T>` @@ -204,6 +209,7 @@ where /// /// # Safety /// Writing to `ptr` must be safe, as if by `<*mut [T; N]>::write_unaligned`. + #[inline] const unsafe fn store(self, ptr: *mut [T; N]) { // There are potentially simpler ways to write this function, but this should result in // LLVM `store <N x T>` @@ -216,6 +222,7 @@ where } /// Converts an array to a SIMD vector. + #[inline] pub const fn from_array(array: [T; N]) -> Self { // SAFETY: `&array` is safe to read. // @@ -228,6 +235,7 @@ where } /// Converts a SIMD vector to an array. + #[inline] pub const fn to_array(self) -> [T; N] { let mut tmp = core::mem::MaybeUninit::uninit(); // SAFETY: writing to `tmp` is safe and initializes it. @@ -259,6 +267,8 @@ where /// assert_eq!(v.as_array(), &[1, 2, 3, 4]); /// ``` #[must_use] + #[inline] + #[track_caller] pub const fn from_slice(slice: &[T]) -> Self { assert!( slice.len() >= Self::LANES, @@ -287,6 +297,8 @@ where /// v.copy_to_slice(&mut dest); /// assert_eq!(&dest, &[1, 2, 3, 4, 0, 0]); /// ``` + #[inline] + #[track_caller] pub fn copy_to_slice(self, slice: &mut [T]) { assert!( slice.len() >= Self::LANES, @@ -297,76 +309,6 @@ where unsafe { self.store(slice.as_mut_ptr().cast()) } } - /// Performs elementwise conversion of a SIMD vector's elements to another SIMD-valid type. - /// - /// This follows the semantics of Rust's `as` conversion for casting integers between - /// signed and unsigned (interpreting integers as 2s complement, so `-1` to `U::MAX` and - /// `1 << (U::BITS -1)` becoming `I::MIN` ), and from floats to integers (truncating, - /// or saturating at the limits) for each element. - /// - /// # Examples - /// ``` - /// # #![feature(portable_simd)] - /// # use core::simd::Simd; - /// let floats: Simd<f32, 4> = Simd::from_array([1.9, -4.5, f32::INFINITY, f32::NAN]); - /// let ints = floats.cast::<i32>(); - /// assert_eq!(ints, Simd::from_array([1, -4, i32::MAX, 0])); - /// - /// // Formally equivalent, but `Simd::cast` can optimize better. - /// assert_eq!(ints, Simd::from_array(floats.to_array().map(|x| x as i32))); - /// - /// // The float conversion does not round-trip. - /// let floats_again = ints.cast(); - /// assert_ne!(floats, floats_again); - /// assert_eq!(floats_again, Simd::from_array([1.0, -4.0, 2147483647.0, 0.0])); - /// ``` - #[must_use] - #[inline] - pub fn cast<U: SimdCast>(self) -> Simd<U, N> - where - T: SimdCast, - { - // Safety: supported types are guaranteed by SimdCast - unsafe { intrinsics::simd_as(self) } - } - - /// Casts a vector of pointers to another pointer type. - #[must_use] - #[inline] - pub fn cast_ptr<U>(self) -> Simd<U, N> - where - T: SimdCastPtr<U>, - U: SimdElement, - { - // Safety: supported types are guaranteed by SimdCastPtr - unsafe { intrinsics::simd_cast_ptr(self) } - } - - /// Rounds toward zero and converts to the same-width integer type, assuming that - /// the value is finite and fits in that type. - /// - /// # Safety - /// The value must: - /// - /// * Not be NaN - /// * Not be infinite - /// * Be representable in the return type, after truncating off its fractional part - /// - /// If these requirements are infeasible or costly, consider using the safe function [cast], - /// which saturates on conversion. - /// - /// [cast]: Simd::cast - #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - pub unsafe fn to_int_unchecked<I>(self) -> Simd<I, N> - where - T: core::convert::FloatToInt<I> + SimdCast, - I: SimdCast, - { - // Safety: supported types are guaranteed by SimdCast, the caller is responsible for the extra invariants - unsafe { intrinsics::simd_cast(self) } - } - /// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector. /// If an index is out-of-bounds, the element is instead selected from the `or` vector. /// @@ -717,6 +659,7 @@ where LaneCount<N>: SupportedLaneCount, T: SimdElement, { + #[inline] fn clone(&self) -> Self { *self } @@ -861,6 +804,7 @@ where LaneCount<N>: SupportedLaneCount, T: SimdElement, { + #[inline] fn from(array: [T; N]) -> Self { Self::from_array(array) } @@ -871,6 +815,7 @@ where LaneCount<N>: SupportedLaneCount, T: SimdElement, { + #[inline] fn from(vector: Simd<T, N>) -> Self { vector.to_array() } @@ -883,6 +828,7 @@ where { type Error = core::array::TryFromSliceError; + #[inline] fn try_from(slice: &[T]) -> Result<Self, core::array::TryFromSliceError> { Ok(Self::from_array(slice.try_into()?)) } @@ -895,6 +841,7 @@ where { type Error = core::array::TryFromSliceError; + #[inline] fn try_from(slice: &mut [T]) -> Result<Self, core::array::TryFromSliceError> { Ok(Self::from_array(slice.try_into()?)) } diff --git a/library/portable-simd/crates/core_simd/tests/cast.rs b/library/portable-simd/crates/core_simd/tests/cast.rs index ab5650f0713..00545936ea2 100644 --- a/library/portable-simd/crates/core_simd/tests/cast.rs +++ b/library/portable-simd/crates/core_simd/tests/cast.rs @@ -2,7 +2,8 @@ macro_rules! cast_types { ($start:ident, $($target:ident),*) => { mod $start { - use core_simd::simd::Simd; + #[allow(unused)] + use core_simd::simd::{Simd, SimdInt, SimdUint, SimdFloat}; type Vector<const N: usize> = Simd<$start, N>; $( mod $target { diff --git a/library/portable-simd/crates/core_simd/tests/round.rs b/library/portable-simd/crates/core_simd/tests/round.rs index 8b9638ad466..aacf7bd3bcc 100644 --- a/library/portable-simd/crates/core_simd/tests/round.rs +++ b/library/portable-simd/crates/core_simd/tests/round.rs @@ -53,6 +53,7 @@ macro_rules! float_rounding_test { test_helpers::test_lanes! { fn to_int_unchecked<const LANES: usize>() { + use core_simd::simd::SimdFloat; // The maximum integer that can be represented by the equivalently sized float has // all of the mantissa digits set to 1, pushed up to the MSB. const ALL_MANTISSA_BITS: IntScalar = ((1 << <Scalar>::MANTISSA_DIGITS) - 1); diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 77b657fd868..eb4815d0cdf 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -18,8 +18,7 @@ panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } libc = { version = "0.2.146", default-features = false, features = ['rustc-dep-of-std'], public = true } -# FIXME(Nilstrieb): https://github.com/rust-lang/compiler-builtins/pull/532/files#r1249354225 -compiler_builtins = { version = "=0.1.93" } +compiler_builtins = { version = "0.1.95" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.14", default-features = false, features = ['rustc-dep-of-std'] } diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index a66e6ccf673..7097dfef88d 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -53,7 +53,7 @@ pub struct BufReader<R: ?Sized> { } impl<R: Read> BufReader<R> { - /// Creates a new `BufReader<R>` with a default buffer capacity. The default is currently 8 KB, + /// Creates a new `BufReader<R>` with a default buffer capacity. The default is currently 8 KiB, /// but may change in the future. /// /// # Examples diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index 0e2450655e5..0f04f291117 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -81,7 +81,7 @@ pub struct BufWriter<W: ?Sized + Write> { } impl<W: Write> BufWriter<W> { - /// Creates a new `BufWriter<W>` with a default buffer capacity. The default is currently 8 KB, + /// Creates a new `BufWriter<W>` with a default buffer capacity. The default is currently 8 KiB, /// but may change in the future. /// /// # Examples diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index da08c018d0e..72b9ad3480b 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -241,7 +241,6 @@ #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] -#![feature(c_str_literals)] #![feature(c_unwind)] #![feature(cfg_target_thread_local)] #![feature(concat_idents)] diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 9da74a5ddb5..8f3201b0091 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1904,8 +1904,8 @@ impl FromInner<imp::ExitCode> for ExitCode { } impl Child { - /// Forces the child process to exit. If the child has already exited, an [`InvalidInput`] - /// error is returned. + /// Forces the child process to exit. If the child has already exited, `Ok(())` + /// is returned. /// /// The mapping to [`ErrorKind`]s is not part of the compatibility contract of the function. /// @@ -1920,7 +1920,7 @@ impl Child { /// /// let mut command = Command::new("yes"); /// if let Ok(mut child) = command.spawn() { - /// child.kill().expect("command wasn't running"); + /// child.kill().expect("command couldn't be killed"); /// } else { /// println!("yes command didn't start"); /// } diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs index d7f4d335de3..366b591466c 100644 --- a/library/std/src/process/tests.rs +++ b/library/std/src/process/tests.rs @@ -582,3 +582,18 @@ fn run_canonical_bat_script() { assert!(output.status.success()); assert_eq!(String::from_utf8_lossy(&output.stdout).trim(), "Hello, fellow Rustaceans!"); } + +#[test] +fn terminate_exited_process() { + let mut cmd = if cfg!(target_os = "android") { + let mut p = shell_cmd(); + p.args(&["-c", "true"]); + p + } else { + known_command() + }; + let mut p = cmd.stdout(Stdio::null()).spawn().unwrap(); + p.wait().unwrap(); + assert!(p.kill().is_ok()); + assert!(p.kill().is_ok()); +} diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs index f8fa81e6ef1..eafd6821f54 100644 --- a/library/std/src/sys/unix/args.rs +++ b/library/std/src/sys/unix/args.rs @@ -242,15 +242,13 @@ mod imp { let mut res = Vec::new(); unsafe { - let process_info_sel = - sel_registerName(c"processInfo".as_ptr() as *const libc::c_uchar); - let arguments_sel = sel_registerName(c"arguments".as_ptr() as *const libc::c_uchar); - let utf8_sel = sel_registerName(c"UTF8String".as_ptr() as *const libc::c_uchar); - let count_sel = sel_registerName(c"count".as_ptr() as *const libc::c_uchar); - let object_at_sel = - sel_registerName(c"objectAtIndex:".as_ptr() as *const libc::c_uchar); - - let klass = objc_getClass(c"NSProcessInfo".as_ptr() as *const libc::c_uchar); + let process_info_sel = sel_registerName("processInfo\0".as_ptr()); + let arguments_sel = sel_registerName("arguments\0".as_ptr()); + let utf8_sel = sel_registerName("UTF8String\0".as_ptr()); + let count_sel = sel_registerName("count\0".as_ptr()); + let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr()); + + let klass = objc_getClass("NSProcessInfo\0".as_ptr()); let info = objc_msgSend(klass, process_info_sel); let args = objc_msgSend(info, arguments_sel); diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 9cf5cfcc8d5..fbc7f04ce9a 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -1097,7 +1097,7 @@ impl File { cfg_has_statx! { if let Some(ret) = unsafe { try_statx( fd, - c"".as_ptr() as *const c_char, + b"\0" as *const _ as *const c_char, libc::AT_EMPTY_PATH | libc::AT_STATX_SYNC_AS_STAT, libc::STATX_ALL, ) } { diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 1b72e21a832..326f1481e19 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -1,5 +1,6 @@ #![allow(missing_docs, nonstandard_style)] +use crate::ffi::CStr; use crate::io::ErrorKind; pub use self::rand::hashmap_random_keys; @@ -74,7 +75,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { // thread-id for the main thread and so renaming the main thread will rename the // process and we only want to enable this on platforms we've tested. if cfg!(target_os = "macos") { - thread::Thread::set_name(&c"main"); + thread::Thread::set_name(&CStr::from_bytes_with_nul_unchecked(b"main\0")); } unsafe fn sanitize_standard_fds() { @@ -121,7 +122,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { if pfd.revents & libc::POLLNVAL == 0 { continue; } - if open64(c"/dev/null".as_ptr().cast(), libc::O_RDWR, 0) == -1 { + if open64("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 { // If the stream is closed but we failed to reopen it, abort the // process. Otherwise we wouldn't preserve the safety of // operations on the corresponding Rust object Stdin, Stdout, or @@ -151,7 +152,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { use libc::open64; for fd in 0..3 { if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF { - if open64(c"/dev/null".as_ptr().cast(), libc::O_RDWR, 0) == -1 { + if open64("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 { // If the stream is closed but we failed to reopen it, abort the // process. Otherwise we wouldn't preserve the safety of // operations on the corresponding Rust object Stdin, Stdout, or diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index 5f316b12b62..640648e8707 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -24,11 +24,11 @@ cfg_if::cfg_if! { if #[cfg(target_os = "fuchsia")] { // fuchsia doesn't have /dev/null } else if #[cfg(target_os = "redox")] { - const DEV_NULL: &CStr = c"null:"; + const DEV_NULL: &str = "null:\0"; } else if #[cfg(target_os = "vxworks")] { - const DEV_NULL: &CStr = c"/null"; + const DEV_NULL: &str = "/null\0"; } else { - const DEV_NULL: &CStr = c"/dev/null"; + const DEV_NULL: &str = "/dev/null\0"; } } @@ -474,7 +474,8 @@ impl Stdio { let mut opts = OpenOptions::new(); opts.read(readable); opts.write(!readable); - let fd = File::open_c(DEV_NULL, &opts)?; + let path = unsafe { CStr::from_ptr(DEV_NULL.as_ptr() as *const _) }; + let fd = File::open_c(&path, &opts)?; Ok((ChildStdio::Owned(fd.into_inner()), None)) } diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 129e7643661..0ce93af66ac 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -762,12 +762,9 @@ impl Process { pub fn kill(&mut self) -> io::Result<()> { // If we've already waited on this process then the pid can be recycled // and used for another process, and we probably shouldn't be killing - // random processes, so just return an error. + // random processes, so return Ok because the process has exited already. if self.status.is_some() { - Err(io::const_io_error!( - ErrorKind::InvalidInput, - "invalid argument: can't kill an exited process", - )) + Ok(()) } else { cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop) } diff --git a/library/std/src/sys/unix/process/process_vxworks.rs b/library/std/src/sys/unix/process/process_vxworks.rs index c40e7ada03c..f70d3cb396b 100644 --- a/library/std/src/sys/unix/process/process_vxworks.rs +++ b/library/std/src/sys/unix/process/process_vxworks.rs @@ -144,12 +144,9 @@ impl Process { pub fn kill(&mut self) -> io::Result<()> { // If we've already waited on this process then the pid can be recycled // and used for another process, and we probably shouldn't be killing - // random processes, so just return an error. + // random processes, so return Ok because the process has exited already. if self.status.is_some() { - Err(io::const_io_error!( - ErrorKind::InvalidInput, - "invalid argument: can't kill an exited process", - )) + Ok(()) } else { cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop) } diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 893f8b8df3f..4f2d9cf3655 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -163,9 +163,10 @@ impl Thread { #[cfg(target_os = "netbsd")] pub fn set_name(name: &CStr) { unsafe { + let cname = CStr::from_bytes_with_nul_unchecked(b"%s\0".as_slice()); let res = libc::pthread_setname_np( libc::pthread_self(), - c"%s".as_ptr(), + cname.as_ptr(), name.as_ptr() as *mut libc::c_void, ); debug_assert_eq!(res, 0); diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index b1b9e84fce9..d9ccba0e9da 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -321,7 +321,7 @@ pub unsafe fn NtWriteFile( // Functions that aren't available on every version of Windows that we support, // but we still use them and just provide some form of a fallback implementation. compat_fn_with_fallback! { - pub static KERNEL32: &CStr = c"kernel32"; + pub static KERNEL32: &CStr = ansi_str!("kernel32"); // >= Win10 1607 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription @@ -354,7 +354,7 @@ compat_fn_optional! { } compat_fn_with_fallback! { - pub static NTDLL: &CStr = c"ntdll"; + pub static NTDLL: &CStr = ansi_str!("ntdll"); pub fn NtCreateKeyedEvent( KeyedEventHandle: LPHANDLE, diff --git a/library/std/src/sys/windows/compat.rs b/library/std/src/sys/windows/compat.rs index 649cc4bfdbf..4fe95d41116 100644 --- a/library/std/src/sys/windows/compat.rs +++ b/library/std/src/sys/windows/compat.rs @@ -228,9 +228,9 @@ macro_rules! compat_fn_optional { /// Load all needed functions from "api-ms-win-core-synch-l1-2-0". pub(super) fn load_synch_functions() { fn try_load() -> Option<()> { - const MODULE_NAME: &CStr = c"api-ms-win-core-synch-l1-2-0"; - const WAIT_ON_ADDRESS: &CStr = c"WaitOnAddress"; - const WAKE_BY_ADDRESS_SINGLE: &CStr = c"WakeByAddressSingle"; + const MODULE_NAME: &CStr = ansi_str!("api-ms-win-core-synch-l1-2-0"); + const WAIT_ON_ADDRESS: &CStr = ansi_str!("WaitOnAddress"); + const WAKE_BY_ADDRESS_SINGLE: &CStr = ansi_str!("WakeByAddressSingle"); // Try loading the library and all the required functions. // If any step fails, then they all fail. diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index b11c8962203..bcc172b0fae 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -1,6 +1,6 @@ #![allow(missing_docs, nonstandard_style)] -use crate::ffi::{OsStr, OsString}; +use crate::ffi::{CStr, OsStr, OsString}; use crate::io::ErrorKind; use crate::mem::MaybeUninit; use crate::os::windows::ffi::{OsStrExt, OsStringExt}; @@ -51,7 +51,7 @@ pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) { // Normally, `thread::spawn` will call `Thread::set_name` but since this thread already // exists, we have to call it ourselves. - thread::Thread::set_name(&c"main"); + thread::Thread::set_name(&CStr::from_bytes_with_nul_unchecked(b"main\0")); } // SAFETY: must be called only once during runtime cleanup. diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index a573a05c39c..e3493cbb850 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -595,7 +595,16 @@ pub struct Process { impl Process { pub fn kill(&mut self) -> io::Result<()> { - cvt(unsafe { c::TerminateProcess(self.handle.as_raw_handle(), 1) })?; + let result = unsafe { c::TerminateProcess(self.handle.as_raw_handle(), 1) }; + if result == c::FALSE { + let error = unsafe { c::GetLastError() }; + // TerminateProcess returns ERROR_ACCESS_DENIED if the process has already been + // terminated (by us, or for any other reason). So check if the process was actually + // terminated, and if so, do not return an error. + if error != c::ERROR_ACCESS_DENIED || self.try_wait().is_err() { + return Err(crate::io::Error::from_raw_os_error(error as i32)); + } + } Ok(()) } diff --git a/rustfmt.toml b/rustfmt.toml index 597ef5b9052..88700779e87 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -16,6 +16,8 @@ ignore = [ "tests", # do not format submodules + # FIXME: sync submodule list with tidy/bootstrap/etc + # tidy/src/walk.rs:filter_dirs "library/backtrace", "library/portable-simd", "library/stdarch", @@ -31,10 +33,8 @@ ignore = [ "src/tools/cargo", "src/tools/clippy", "src/tools/miri", - "src/tools/rls", "src/tools/rust-analyzer", "src/tools/rustfmt", - "src/tools/rust-installer", # these are ignored by a standard cargo fmt run "compiler/rustc_codegen_cranelift/y.rs", # running rustfmt breaks this file diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index dc05f47ee9c..a882336c3c4 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -304,7 +304,7 @@ pub enum Subcommand { ./x.py test library/std --test-args hash_map ./x.py test library/std --stage 0 --no-doc ./x.py test tests/ui --bless - ./x.py test tests/ui --compare-mode chalk + ./x.py test tests/ui --compare-mode next-solver Note that `test tests/* --stage N` does NOT depend on `build compiler/rustc --stage N`; just like `build library/std --stage N` it tests the compiler produced by the previous stage. diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 6a51450a777..0a7aff62257 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -599,6 +599,9 @@ impl Build { let mut git = self.config.git(); if let Some(branch) = current_branch { + // If there is a tag named after the current branch, git will try to disambiguate by prepending `heads/` to the branch name. + // This syntax isn't accepted by `branch.{branch}`. Strip it. + let branch = branch.strip_prefix("heads/").unwrap_or(&branch); git.arg("-c").arg(format!("branch.{branch}.remote=origin")); } git.args(&["submodule", "update", "--init", "--recursive", "--depth=1"]); diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs index 4752b1f7ea1..c4916a21c0f 100644 --- a/src/bootstrap/llvm.rs +++ b/src/bootstrap/llvm.rs @@ -380,7 +380,10 @@ impl Step for Llvm { cfg.define("LLVM_LINK_LLVM_DYLIB", "ON"); } - if target.starts_with("riscv") && !target.contains("freebsd") && !target.contains("openbsd") + if target.starts_with("riscv") + && !target.contains("freebsd") + && !target.contains("openbsd") + && !target.contains("netbsd") { // RISC-V GCC erroneously requires linking against // `libatomic` when using 1-byte and 2-byte C++ diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 75e7bd6aa24..e4cc88c64a5 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -2219,6 +2219,11 @@ fn prepare_cargo_test( ) -> Command { let mut cargo = cargo.into(); + // If bless is passed, give downstream crates a way to use it + if builder.config.cmd.bless() { + cargo.env("RUSTC_BLESS", "1"); + } + // Pass in some standard flags then iterate over the graph we've discovered // in `cargo metadata` with the maps above and figure out what `-p` // arguments need to get passed. diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 126f0b1eb31..06c03178862 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -289,7 +289,7 @@ bootstrap_tool!( Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true, allow_features = "test"; BuildManifest, "src/tools/build-manifest", "build-manifest"; RemoteTestClient, "src/tools/remote-test-client", "remote-test-client"; - RustInstaller, "src/tools/rust-installer", "rust-installer", is_external_tool = true; + RustInstaller, "src/tools/rust-installer", "rust-installer"; RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes"; ExpandYamlAnchors, "src/tools/expand-yaml-anchors", "expand-yaml-anchors"; LintDocs, "src/tools/lint-docs", "lint-docs"; diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile deleted file mode 100644 index d45ef0a7d07..00000000000 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile +++ /dev/null @@ -1,54 +0,0 @@ -FROM ubuntu:22.04 - -ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install -y --no-install-recommends \ - g++ \ - gcc-multilib \ - make \ - ninja-build \ - file \ - curl \ - ca-certificates \ - python3 \ - git \ - cmake \ - sudo \ - gdb \ - llvm-14-tools \ - llvm-14-dev \ - libedit-dev \ - libssl-dev \ - pkg-config \ - zlib1g-dev \ - xz-utils \ - nodejs \ - mingw-w64 \ - && rm -rf /var/lib/apt/lists/* - -COPY scripts/sccache.sh /scripts/ -RUN sh /scripts/sccache.sh - -# We are disabling CI LLVM since this builder is intentionally using a host -# LLVM, rather than the typical src/llvm-project LLVM. -ENV NO_DOWNLOAD_CI_LLVM 1 - -# This is not the latest LLVM version, so some components required by tests may -# be missing. -ENV IS_NOT_LATEST_LLVM 1 - -# Using llvm-link-shared due to libffi issues -- see #34486 -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ - --llvm-root=/usr/lib/llvm-14 \ - --enable-llvm-link-shared \ - --set rust.thin-lto-import-instr-limit=10 - -ENV SCRIPT ../x.py --stage 1 test --exclude src/tools/tidy && \ - # Run the `mir-opt` tests again but this time for a 32-bit target. - # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have - # both 32-bit and 64-bit outputs updated by the PR author, before - # the PR is approved and tested for merging. - # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`, - # despite having different output on 32-bit vs 64-bit targets. - ../x.py --stage 1 test tests/mir-opt \ - --host='' --target=i686-unknown-linux-gnu diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile index 1f28b939778..93d18bcf1b1 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile @@ -49,20 +49,6 @@ ENV RUST_CONFIGURE_ARGS \ --enable-llvm-link-shared \ --set rust.thin-lto-import-instr-limit=10 -# NOTE: intentionally uses all of `x.py`, `x`, and `x.ps1` to make sure they all work on Linux. -ENV SCRIPT ../x.py --stage 2 test --exclude src/tools/tidy && \ - # Run the `mir-opt` tests again but this time for a 32-bit target. - # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have - # both 32-bit and 64-bit outputs updated by the PR author, before - # the PR is approved and tested for merging. - # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`, - # despite having different output on 32-bit vs 64-bit targets. - ../x --stage 2 test tests/mir-opt \ - --host='' --target=i686-unknown-linux-gnu && \ - # Run the UI test suite again, but in `--pass=check` mode - # - # This is intended to make sure that both `--pass=check` continues to - # work. - # - ../x.ps1 --stage 2 test tests/ui --pass=check \ - --host='' --target=i686-unknown-linux-gnu +COPY host-x86_64/x86_64-gnu-llvm-14/script.sh /tmp/ + +ENV SCRIPT /tmp/script.sh diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/script.sh b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/script.sh new file mode 100755 index 00000000000..0120fd98298 --- /dev/null +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/script.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +set -ex + +# Only run the stage 1 tests on merges, not on PR CI jobs. +if [[ -z "${PR_CI_JOB}" ]]; then +../x.py --stage 1 test --exclude src/tools/tidy && \ + # Run the `mir-opt` tests again but this time for a 32-bit target. + # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have + # both 32-bit and 64-bit outputs updated by the PR author, before + # the PR is approved and tested for merging. + # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`, + # despite having different output on 32-bit vs 64-bit targets. + ../x.py --stage 1 test tests/mir-opt \ + --host='' --target=i686-unknown-linux-gnu +fi + +# NOTE: intentionally uses all of `x.py`, `x`, and `x.ps1` to make sure they all work on Linux. +../x.py --stage 2 test --exclude src/tools/tidy && \ + # Run the `mir-opt` tests again but this time for a 32-bit target. + # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have + # both 32-bit and 64-bit outputs updated by the PR author, before + # the PR is approved and tested for merging. + # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`, + # despite having different output on 32-bit vs 64-bit targets. + ../x --stage 2 test tests/mir-opt \ + --host='' --target=i686-unknown-linux-gnu && \ + # Run the UI test suite again, but in `--pass=check` mode + # + # This is intended to make sure that both `--pass=check` continues to + # work. + # + ../x.ps1 --stage 2 test tests/ui --pass=check \ + --host='' --target=i686-unknown-linux-gnu diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 0a098467d94..4b218d57727 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -263,6 +263,7 @@ docker \ --env CI_JOB_NAME="${CI_JOB_NAME-$IMAGE}" \ --env BASE_COMMIT="$BASE_COMMIT" \ --env DIST_TRY_BUILD \ + --env PR_CI_JOB \ --init \ --rm \ rust-ci \ diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index cb12042c117..24fc72e660a 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -311,6 +311,7 @@ jobs: name: PR - ${{ matrix.name }} env: <<: [*shared-ci-variables, *public-variables] + PR_CI_JOB: 1 if: github.event_name == 'pull_request' continue-on-error: ${{ matrix.name == 'mingw-check-tidy' }} strategy: @@ -374,18 +375,6 @@ jobs: - name: dist-loongarch64-linux <<: *job-linux-8c - - name: dist-mips-linux - <<: *job-linux-8c - - - name: dist-mips64-linux - <<: *job-linux-8c - - - name: dist-mips64el-linux - <<: *job-linux-8c - - - name: dist-mipsel-linux - <<: *job-linux-8c - - name: dist-powerpc-linux <<: *job-linux-8c @@ -485,11 +474,6 @@ jobs: RUST_BACKTRACE: 1 <<: *job-linux-8c - - name: x86_64-gnu-llvm-14-stage1 - env: - RUST_BACKTRACE: 1 - <<: *job-linux-8c - - name: x86_64-gnu-nopt <<: *job-linux-4c @@ -606,16 +590,10 @@ jobs: SCRIPT: make ci-msvc <<: *job-windows-8c - - name: x86_64-msvc-cargo - env: - SCRIPT: python x.py --stage 2 test src/tools/cargotest src/tools/cargo - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld - <<: *job-windows-8c - - - name: x86_64-msvc-tools + - name: x86_64-msvc-ext env: - SCRIPT: src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstate/toolstates.json windows - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstate/toolstates.json + SCRIPT: python x.py --stage 2 test src/tools/cargotest src/tools/cargo && src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstate/toolstates.json windows + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld --save-toolstates=/tmp/toolstate/toolstates.json DEPLOY_TOOLSTATES_JSON: toolstates-windows.json <<: *job-windows-8c diff --git a/src/ci/run.sh b/src/ci/run.sh index 5363086f68b..48fb40d6a6d 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -188,6 +188,7 @@ else fi if [ ! -z "$SCRIPT" ]; then + echo "Executing ${SCRIPT}" sh -x -c "$SCRIPT" else do_make() { diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 6d1729e57b1..d2a25e612ec 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -87,7 +87,7 @@ target | notes `aarch64-unknown-linux-musl` | ARM64 Linux with MUSL `arm-unknown-linux-gnueabi` | ARMv6 Linux (kernel 3.2, glibc 2.17) `arm-unknown-linux-gnueabihf` | ARMv6 Linux, hardfloat (kernel 3.2, glibc 2.17) -`armv7-unknown-linux-gnueabihf` | ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17) +`armv7-unknown-linux-gnueabihf` | ARMv7-A Linux, hardfloat (kernel 3.2, glibc 2.17) [`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36) `mips-unknown-linux-gnu` | MIPS Linux (kernel 4.4, glibc 2.23) `mips64-unknown-linux-gnuabi64` | MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23) @@ -133,17 +133,17 @@ target | std | notes `aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat `aarch64-unknown-none` | * | Bare ARM64, hardfloat [`aarch64-unknown-uefi`](platform-support/unknown-uefi.md) | * | ARM64 UEFI -[`arm-linux-androideabi`](platform-support/android.md) | ✓ | ARMv7 Android +[`arm-linux-androideabi`](platform-support/android.md) | ✓ | ARMv6 Android `arm-unknown-linux-musleabi` | ✓ | ARMv6 Linux with MUSL `arm-unknown-linux-musleabihf` | ✓ | ARMv6 Linux with MUSL, hardfloat `armebv7r-none-eabi` | * | Bare ARMv7-R, Big Endian `armebv7r-none-eabihf` | * | Bare ARMv7-R, Big Endian, hardfloat `armv5te-unknown-linux-gnueabi` | ✓ | ARMv5TE Linux (kernel 4.4, glibc 2.23) `armv5te-unknown-linux-musleabi` | ✓ | ARMv5TE Linux with MUSL -[`armv7-linux-androideabi`](platform-support/android.md) | ✓ | ARMv7a Android -`armv7-unknown-linux-gnueabi` | ✓ |ARMv7 Linux (kernel 4.15, glibc 2.27) -`armv7-unknown-linux-musleabi` | ✓ |ARMv7 Linux with MUSL -`armv7-unknown-linux-musleabihf` | ✓ | ARMv7 Linux with MUSL, hardfloat +[`armv7-linux-androideabi`](platform-support/android.md) | ✓ | ARMv7-A Android +`armv7-unknown-linux-gnueabi` | ✓ | ARMv7-A Linux (kernel 4.15, glibc 2.27) +`armv7-unknown-linux-musleabi` | ✓ | ARMv7-A Linux with MUSL +`armv7-unknown-linux-musleabihf` | ✓ | ARMv7-A Linux with MUSL, hardfloat `armv7a-none-eabi` | * | Bare ARMv7-A `armv7r-none-eabi` | * | Bare ARMv7-R `armv7r-none-eabihf` | * | Bare ARMv7-R, hardfloat @@ -167,15 +167,15 @@ target | std | notes `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA) `sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23) `sparcv9-sun-solaris` | ✓ | SPARC Solaris 10/11, illumos -`thumbv6m-none-eabi` | * | Bare Cortex-M0, M0+, M1 -`thumbv7em-none-eabi` | * | Bare Cortex-M4, M7 -`thumbv7em-none-eabihf` | * | Bare Cortex-M4F, M7F, FPU, hardfloat -`thumbv7m-none-eabi` | * | Bare Cortex-M3 -[`thumbv7neon-linux-androideabi`](platform-support/android.md) | ✓ | Thumb2-mode ARMv7a Android with NEON -`thumbv7neon-unknown-linux-gnueabihf` | ✓ | Thumb2-mode ARMv7a Linux with NEON (kernel 4.4, glibc 2.23) -`thumbv8m.base-none-eabi` | * | ARMv8-M Baseline -`thumbv8m.main-none-eabi` | * | ARMv8-M Mainline -`thumbv8m.main-none-eabihf` | * | ARMv8-M Mainline, hardfloat +`thumbv6m-none-eabi` | * | Bare ARMv6-M +`thumbv7em-none-eabi` | * | Bare ARMv7E-M +`thumbv7em-none-eabihf` | * | Bare ARMV7E-M, hardfloat +`thumbv7m-none-eabi` | * | Bare ARMv7-M +[`thumbv7neon-linux-androideabi`](platform-support/android.md) | ✓ | Thumb2-mode ARMv7-A Android with NEON +`thumbv7neon-unknown-linux-gnueabihf` | ✓ | Thumb2-mode ARMv7-A Linux with NEON (kernel 4.4, glibc 2.23) +`thumbv8m.base-none-eabi` | * | Bare ARMv8-M Baseline +`thumbv8m.main-none-eabi` | * | Bare ARMv8-M Mainline +`thumbv8m.main-none-eabihf` | * | Bare ARMv8-M Mainline, hardfloat `wasm32-unknown-emscripten` | ✓ | WebAssembly via Emscripten `wasm32-unknown-unknown` | ✓ | WebAssembly `wasm32-wasi` | ✓ | WebAssembly with WASI @@ -234,26 +234,26 @@ target | std | host | notes [`aarch64_be-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD (big-endian) [`arm64_32-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARM Apple WatchOS 64-bit with 32-bit pointers [`armeb-unknown-linux-gnueabi`](platform-support/armeb-unknown-linux-gnueabi.md) | ✓ | ? | ARM BE8 the default ARM big-endian architecture since [ARMv6](https://developer.arm.com/documentation/101754/0616/armlink-Reference/armlink-Command-line-Options/--be8?lang=en). -`armv4t-none-eabi` | * | | ARMv4T A32 -`armv4t-unknown-linux-gnueabi` | ? | | -[`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | ARMv5TE A32 +`armv4t-none-eabi` | * | | Bare ARMv4T +`armv4t-unknown-linux-gnueabi` | ? | | ARMv4T Linux +[`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Bare ARMv5TE `armv5te-unknown-linux-uclibceabi` | ? | | ARMv5TE Linux with uClibc `armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD [`armv6-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | ARMv6 NetBSD w/hard-float [`armv6k-nintendo-3ds`](platform-support/armv6k-nintendo-3ds.md) | ? | | ARMv6K Nintendo 3DS, Horizon (Requires devkitARM toolchain) -`armv7-apple-ios` | ✓ | | ARMv7 iOS, Cortex-a8 -[`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ? | | ARM Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain) -[`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | | ARMv7 OpenHarmony | -[`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | ARMv7 Linux with uClibc, softfloat -[`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | ARMv7 Linux with uClibc, hardfloat -`armv7-unknown-freebsd` | ✓ | ✓ | ARMv7 FreeBSD -[`armv7-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | ARMv7 NetBSD w/hard-float -`armv7-wrs-vxworks-eabihf` | ? | | +`armv7-apple-ios` | ✓ | | ARMv7-A Cortex-A8 iOS +[`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ? | | ARMv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain) +[`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | | ARMv7-A OpenHarmony | +[`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | ARMv7-A Linux with uClibc, softfloat +[`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | ARMv7-A Linux with uClibc, hardfloat +`armv7-unknown-freebsd` | ✓ | ✓ | ARMv7-A FreeBSD +[`armv7-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | ARMv7-A NetBSD w/hard-float +`armv7-wrs-vxworks-eabihf` | ? | | ARMv7-A for VxWorks [`armv7a-kmc-solid_asp3-eabi`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3 [`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3, hardfloat -`armv7a-none-eabihf` | * | | ARM Cortex-A, hardfloat -[`armv7k-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARM Apple WatchOS -`armv7s-apple-ios` | ✓ | | +`armv7a-none-eabihf` | * | | Bare ARMv7-A, hardfloat +[`armv7k-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARMv7-A Apple WatchOS +`armv7s-apple-ios` | ✓ | | ARMv7-A Apple-A6 Apple iOS `avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core` `bpfeb-unknown-none` | * | | BPF (big endian) `bpfel-unknown-none` | * | | BPF (little endian) @@ -305,16 +305,17 @@ target | std | host | notes `riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD `riscv64gc-unknown-fuchsia` | | | RISC-V Fuchsia `riscv64gc-unknown-linux-musl` | | | RISC-V Linux (kernel 4.20, musl 1.2.0) +[`riscv64gc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ? | RISC-V NetBSD [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64 `s390x-unknown-linux-musl` | | | S390x Linux (kernel 3.2, MUSL) `sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux [`sparc64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/sparc64 [`sparc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/sparc64 -`thumbv4t-none-eabi` | * | | ARMv4T T32 -[`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | ARMv5TE T32 +`thumbv4t-none-eabi` | * | | Thumb-mode Bare ARMv4T +[`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Thumb-mode Bare ARMv5TE `thumbv7a-pc-windows-msvc` | ? | | `thumbv7a-uwp-windows-msvc` | ✓ | | -`thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode ARMv7a Linux with NEON, MUSL +`thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode ARMv7-A Linux with NEON, MUSL [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? | | WebAssembly `x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst on x86_64 [`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ? | | x86 64-bit tvOS diff --git a/src/doc/rustc/src/platform-support/netbsd.md b/src/doc/rustc/src/platform-support/netbsd.md index a1969524a20..23f4488de6e 100644 --- a/src/doc/rustc/src/platform-support/netbsd.md +++ b/src/doc/rustc/src/platform-support/netbsd.md @@ -22,6 +22,7 @@ are currently defined running NetBSD: | `i686-unknown-netbsd` | [32-bit i386 with SSE](https://wiki.netbsd.org/ports/i386/) | | `mipsel-unknown-netbsd` | [32-bit mips, requires mips32 cpu support](https://wiki.netbsd.org/ports/evbmips/) | | `powerpc-unknown-netbsd` | [Various 32-bit PowerPC systems, e.g. MacPPC](https://wiki.netbsd.org/ports/macppc/) | +| `riscv64gc-unknown-netbsd` | [64-bit RISC-V](https://wiki.netbsd.org/ports/riscv/) | `sparc64-unknown-netbsd` | [Sun UltraSPARC systems](https://wiki.netbsd.org/ports/sparc64/) | All use the "native" `stdc++` library which goes along with the natively diff --git a/src/doc/style-guide/src/SUMMARY.md b/src/doc/style-guide/src/SUMMARY.md index 59fe9fdc669..606485bfb6c 100644 --- a/src/doc/style-guide/src/SUMMARY.md +++ b/src/doc/style-guide/src/SUMMARY.md @@ -9,3 +9,4 @@ - [Other style advice](advice.md) - [`Cargo.toml` conventions](cargo.md) - [Guiding principles and rationale](principles.md) +- [Nightly-only syntax](nightly.md) diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md index f5e37b6c46f..143161da6cf 100644 --- a/src/doc/style-guide/src/expressions.md +++ b/src/doc/style-guide/src/expressions.md @@ -295,8 +295,9 @@ Use parentheses liberally, do not necessarily elide them due to precedence. Tools should not automatically insert or remove parentheses. Do not use spaces to indicate precedence. -If line-breaking, put the operator on a new line and block indent. Put each -sub-expression on its own line. E.g., +If line-breaking, block-indent each subsequent line. For assignment operators, +break after the operator; for all other operators, put the operator on the +subsequent line. Put each sub-expression on its own line: ```rust foo_bar @@ -752,9 +753,9 @@ not put the `if` clause on a newline. E.g., } ``` -If every clause in a pattern is *small*, but does not fit on one line, then the -pattern may be formatted across multiple lines with as many clauses per line as -possible. Again break before a `|`: +If every clause in a pattern is *small*, but the whole pattern does not fit on +one line, then the pattern may be formatted across multiple lines with as many +clauses per line as possible. Again break before a `|`: ```rust foo | bar | baz @@ -763,17 +764,18 @@ possible. Again break before a `|`: } ``` -We define a pattern clause to be *small* if it matches the following grammar: +We define a pattern clause to be *small* if it fits on a single line and +matches "small" in the following grammar: ``` -[small, ntp]: - - single token - - `&[single-line, ntp]` +small: + - small_no_tuple + - unary tuple constructor: `(` small_no_tuple `,` `)` + - `&` small -[small]: - - `[small, ntp]` - - unary tuple constructor `([small, ntp])` - - `&[small]` +small_no_tuple: + - single token + - `&` small_no_tuple ``` E.g., `&&Some(foo)` matches, `Foo(4, Bar)` does not. diff --git a/src/doc/style-guide/src/nightly.md b/src/doc/style-guide/src/nightly.md new file mode 100644 index 00000000000..031811b0e6f --- /dev/null +++ b/src/doc/style-guide/src/nightly.md @@ -0,0 +1,5 @@ +This chapter documents style and formatting for nightly-only syntax. The rest of the style guide documents style for stable Rust syntax; nightly syntax only appears in this chapter. Each section here includes the name of the feature gate, so that searches (e.g. `git grep`) for a nightly feature in the Rust repository also turn up the style guide section. + +Style and formatting for nightly-only syntax should be removed from this chapter and integrated into the appropriate sections of the style guide at the time of stabilization. + +There is no guarantee of the stability of this chapter in contrast to the rest of the style guide. Refer to the style team policy for nightly formatting procedure regarding breaking changes to this chapter. diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b2f9c0bccea..0182d50773d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -342,8 +342,7 @@ pub(crate) fn clean_predicate<'tcx>( // FIXME(generic_const_exprs): should this do something? ty::ClauseKind::ConstEvaluatable(..) | ty::ClauseKind::WellFormed(..) - | ty::ClauseKind::ConstArgHasType(..) - | ty::ClauseKind::TypeWellFormedFromEnv(..) => None, + | ty::ClauseKind::ConstArgHasType(..) => None, } } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index ccfd4cc5b87..b7f455259ef 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -971,6 +971,8 @@ so that we can apply CSS-filters to change the arrow color in themes */ display: flex; padding: 3px; margin-bottom: 5px; + align-items: center; + vertical-align: text-bottom; } .item-name .stab { margin-left: 0.3125em; @@ -982,11 +984,9 @@ so that we can apply CSS-filters to change the arrow color in themes */ color: var(--main-color); background-color: var(--stab-background-color); width: fit-content; - align-items: center; white-space: pre-wrap; border-radius: 3px; - display: inline-flex; - vertical-align: text-bottom; + display: inline; } .stab.portability > code { diff --git a/src/llvm-project b/src/llvm-project -Subproject 22897bce7bfedc9cd3953a33419b34693626350 +Subproject 06248fa7f35136f66114b2f82c29abcefd5f1e9 diff --git a/src/tools/bump-stage0/Cargo.toml b/src/tools/bump-stage0/Cargo.toml index 758b1b139ad..4680a7ab661 100644 --- a/src/tools/bump-stage0/Cargo.toml +++ b/src/tools/bump-stage0/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] anyhow = "1.0.34" curl = "0.4.38" -indexmap = { version = "1.9.1", features = ["serde"] } +indexmap = { version = "2.0.0", features = ["serde"] } serde = { version = "1.0.125", features = ["derive"] } serde_json = { version = "1.0.59", features = ["preserve_order"] } toml = "0.5.7" diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs index 8c3ad24eeed..e8775b08144 100644 --- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs +++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs @@ -61,7 +61,7 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) - ) }) .map_or(false, |assoc_item| { - let proj = cx.tcx.mk_projection(assoc_item.def_id, cx.tcx.mk_substs_trait(ty, [])); + let proj = Ty::new_projection(cx.tcx,assoc_item.def_id, cx.tcx.mk_substs_trait(ty, [])); let nty = cx.tcx.normalize_erasing_regions(cx.param_env, proj); nty.is_bool() diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs index f3347e33077..5c5a4cfce88 100644 --- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs @@ -149,7 +149,7 @@ fn is_ref_iterable<'tcx>( let self_ty = if mutbl.is_mut() { self_ty } else { - cx.tcx.mk_ref(region, TypeAndMut { ty, mutbl }) + Ty::new_ref(cx.tcx,region, TypeAndMut { ty, mutbl }) }; if implements_trait(cx, self_ty, trait_id, &[]) && let Some(ty) = @@ -164,7 +164,7 @@ fn is_ref_iterable<'tcx>( && !self_ty.is_ref() { // Attempt to borrow - let self_ty = cx.tcx.mk_ref(cx.tcx.lifetimes.re_erased, TypeAndMut { + let self_ty = Ty::new_ref(cx.tcx,cx.tcx.lifetimes.re_erased, TypeAndMut { ty: self_ty, mutbl, }); diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index ac209d01406..8ca7af8107f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -215,7 +215,7 @@ fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty: && let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, item, [collect_ty]) && let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions( cx.param_env, - cx.tcx.mk_projection(into_iter_item_proj.def_id, into_iter_item_proj.substs) + Ty::new_projection(cx.tcx,into_iter_item_proj.def_id, into_iter_item_proj.substs) ) { iter_item_ty == into_iter_item_ty @@ -238,7 +238,7 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) - .associated_items(iter_trait) .find_by_name_and_kind(cx.tcx, Ident::with_dummy_span(Symbol::intern("Item")), AssocKind::Type, iter_trait) && let substs = cx.tcx.mk_substs(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))]) - && let proj_ty = cx.tcx.mk_projection(iter_item.def_id, substs) + && let proj_ty = Ty::new_projection(cx.tcx,iter_item.def_id, substs) && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty) { item_ty == EarlyBinder::bind(search_ty).subst(cx.tcx, cx.typeck_results().node_substs(call_id)) diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 16ef24bd4e3..6bd5e9e88c8 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -270,7 +270,7 @@ fn check_other_call_arg<'tcx>( if let Some((n_refs, receiver_ty)) = if n_refs > 0 || is_copy(cx, receiver_ty) { Some((n_refs, receiver_ty)) } else if trait_predicate.def_id() != deref_trait_id { - Some((1, cx.tcx.mk_ref( + Some((1, Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, ty::TypeAndMut { ty: receiver_ty, diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index ece10474715..f11d5773d04 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -17,7 +17,7 @@ use rustc_hir_typeck::expr_use_visitor as euv; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; -use rustc_middle::ty::{self, TypeVisitableExt}; +use rustc_middle::ty::{self, TypeVisitableExt, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; @@ -168,7 +168,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { ( preds.iter().any(|t| cx.tcx.is_diagnostic_item(sym::Borrow, t.def_id())), !preds.is_empty() && { - let ty_empty_region = cx.tcx.mk_imm_ref(cx.tcx.lifetimes.re_erased, ty); + let ty_empty_region = Ty::new_imm_ref(cx.tcx,cx.tcx.lifetimes.re_erased, ty); preds.iter().all(|t| { let ty_params = t.trait_ref.substs.iter().skip(1).collect::<Vec<_>>(); implements_trait(cx, ty_empty_region, t.def_id(), &ty_params) diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 866a04466c9..32213718b27 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -389,11 +389,11 @@ impl<'tcx> DerefTy<'tcx> { fn ty(&self, cx: &LateContext<'tcx>) -> Ty<'tcx> { match *self { Self::Str => cx.tcx.types.str_, - Self::Path => cx.tcx.mk_adt( + Self::Path => Ty::new_adt(cx.tcx, cx.tcx.adt_def(cx.tcx.get_diagnostic_item(sym::Path).unwrap()), List::empty(), ), - Self::Slice(_, ty) => cx.tcx.mk_slice(ty), + Self::Slice(_, ty) => Ty::new_slice(cx.tcx,ty), } } diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs index 2fdd775ad48..c70ce83a9c4 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs @@ -7,6 +7,7 @@ use rustc_ast::util::parser::PREC_PREFIX; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability}; use rustc_lint::{LateContext, LateLintPass, Lint}; +use rustc_middle::ty::Ty; use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::subst::GenericArg; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -134,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { } else if let Some(target_id) = cx.tcx.lang_items().deref_target() { if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions( cx.param_env, - cx.tcx.mk_projection(target_id, cx.tcx.mk_substs(&[GenericArg::from(indexed_ty)])), + Ty::new_projection(cx.tcx,target_id, cx.tcx.mk_substs(&[GenericArg::from(indexed_ty)])), ) { if deref_ty == expr_ty { let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0; diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs index 31a9b69ca15..857d2ad8258 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs @@ -24,7 +24,7 @@ pub(super) fn check<'tcx>( "transmute from a pointer to a pointer", |diag| { if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { - let sugg = arg.as_ty(cx.tcx.mk_ptr(*to_ty)); + let sugg = arg.as_ty(Ty::new_ptr(cx.tcx,*to_ty)); diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified); } }, diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs index 426c7253806..ea9ad99618a 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -64,8 +64,8 @@ pub(super) fn check<'tcx>( }; let ty_to_and_mut = ty::TypeAndMut { ty: *ty_to, mutbl: *to_mutbl }; let sugg_paren = arg - .as_ty(cx.tcx.mk_ptr(ty_from_and_mut)) - .as_ty(cx.tcx.mk_ptr(ty_to_and_mut)); + .as_ty(Ty::new_ptr(cx.tcx,ty_from_and_mut)) + .as_ty(Ty::new_ptr(cx.tcx,ty_to_and_mut)); let sugg = if *to_mutbl == Mutability::Mut { sugg_paren.mut_addr_deref() } else { diff --git a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs index 56207fe767c..b6615410e25 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs @@ -43,7 +43,7 @@ pub(super) fn check<'tcx>( let sugg = if *ptr_ty == rty_and_mut { arg.as_ty(to_ty) } else { - arg.as_ty(cx.tcx.mk_ptr(rty_and_mut)).as_ty(to_ty) + arg.as_ty(Ty::new_ptr(cx.tcx,rty_and_mut)).as_ty(to_ty) }; diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified); diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index dd3cda8ec52..d1cfdc49658 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -689,7 +689,7 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'t mir::ConstantKind::Val(ConstValue::ByRef { alloc, offset: _ }, _) => match result.ty().kind() { ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)), ty::Array(sub_type, len) => match sub_type.kind() { - ty::Float(FloatTy::F32) => match len.kind().try_to_target_usize(lcx.tcx) { + ty::Float(FloatTy::F32) => match len.try_to_target_usize(lcx.tcx) { Some(len) => alloc .inner() .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * usize::try_from(len).unwrap())) @@ -700,7 +700,7 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'t .map(Constant::Vec), _ => None, }, - ty::Float(FloatTy::F64) => match len.kind().try_to_target_usize(lcx.tcx) { + ty::Float(FloatTy::F64) => match len.try_to_target_usize(lcx.tcx) { Some(len) => alloc .inner() .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * usize::try_from(len).unwrap())) @@ -725,13 +725,14 @@ fn field_of_struct<'tcx>( result: mir::ConstantKind<'tcx>, field: &Ident, ) -> Option<mir::ConstantKind<'tcx>> { - if let Some(dc) = lcx.tcx.try_destructure_mir_constant(lcx.param_env.and(result)) + if let mir::ConstantKind::Val(result, ty) = result + && let Some(dc) = lcx.tcx.try_destructure_mir_constant_for_diagnostics((result, ty)) && let Some(dc_variant) = dc.variant && let Some(variant) = adt_def.variants().get(dc_variant) && let Some(field_idx) = variant.fields.iter().position(|el| el.name == field.name) - && let Some(dc_field) = dc.fields.get(field_idx) + && let Some(&(val, ty)) = dc.fields.get(field_idx) { - Some(*dc_field) + Some(mir::ConstantKind::Val(val, ty)) } else { None diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 9c39d22c61b..d650cbe0b13 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -1124,7 +1124,7 @@ pub fn make_normalized_projection<'tcx>( ); return None; } - match tcx.try_normalize_erasing_regions(param_env, tcx.mk_projection(ty.def_id, ty.substs)) { + match tcx.try_normalize_erasing_regions(param_env, Ty::new_projection(tcx,ty.def_id, ty.substs)) { Ok(ty) => Some(ty), Err(e) => { debug_assert!(false, "failed to normalize type `{ty}`: {e:#?}"); @@ -1207,7 +1207,7 @@ pub fn make_normalized_projection_with_regions<'tcx>( .infer_ctxt() .build() .at(&cause, param_env) - .query_normalize(tcx.mk_projection(ty.def_id, ty.substs)) + .query_normalize(Ty::new_projection(tcx,ty.def_id, ty.substs)) { Ok(ty) => Some(ty.value), Err(e) => { diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index c95a125c737..7c17e92d0df 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -107,7 +107,6 @@ string_enum! { #[derive(Clone, Debug, PartialEq)] pub enum CompareMode { Polonius => "polonius", - Chalk => "chalk", NextSolver => "next-solver", NextSolverCoherence => "next-solver-coherence", SplitDwarf => "split-dwarf", diff --git a/src/tools/compiletest/src/read2.rs b/src/tools/compiletest/src/read2.rs index 725f7a1515c..a455a1badc0 100644 --- a/src/tools/compiletest/src/read2.rs +++ b/src/tools/compiletest/src/read2.rs @@ -83,7 +83,7 @@ impl ProcOutput { } let new_len = bytes.len(); - if *filtered_len <= HEAD_LEN + TAIL_LEN { + if (*filtered_len).min(new_len) <= HEAD_LEN + TAIL_LEN { return; } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index fddfbac78d5..672779325ae 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2435,9 +2435,6 @@ impl<'test> TestCx<'test> { Some(CompareMode::Polonius) => { rustc.args(&["-Zpolonius"]); } - Some(CompareMode::Chalk) => { - rustc.args(&["-Ztrait-solver=chalk"]); - } Some(CompareMode::NextSolver) => { rustc.args(&["-Ztrait-solver=next"]); } @@ -4025,8 +4022,11 @@ impl<'test> TestCx<'test> { } fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> String { + let rflags = self.props.run_flags.as_ref(); let cflags = self.props.compile_flags.join(" "); - let json = cflags.contains("--error-format json") + let json = rflags + .map_or(false, |s| s.contains("--format json") || s.contains("--format=json")) + || cflags.contains("--error-format json") || cflags.contains("--error-format pretty-json") || cflags.contains("--error-format=json") || cflags.contains("--error-format=pretty-json") diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 6288ff9beef..3e0c6dadba0 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -1011,7 +1011,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // We have to turn the place into a pointer to use the existing code. // (The pointer type does not matter, so we use a raw pointer.) - let ptr_layout = this.layout_of(this.tcx.mk_mut_ptr(return_place.layout.ty))?; + let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx,return_place.layout.ty))?; let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout); // Reborrow it. With protection! That is part of the point. let new_perm = NewPermission::Uniform { diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index cf0fb42fd1b..df54e91f67f 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -511,7 +511,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // We have to turn the place into a pointer to use the existing code. // (The pointer type does not matter, so we use a raw pointer.) - let ptr_layout = this.layout_of(this.tcx.mk_mut_ptr(return_place.layout.ty))?; + let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx,return_place.layout.ty))?; let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout); // Reborrow it. With protection! That is part of the point. // FIXME: do we truly want a 2phase borrow here? diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 6cf6cb95cf8..ae67e608442 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -8,6 +8,7 @@ use std::task::Poll; use std::thread; use log::info; +use rustc_middle::ty::Ty; use crate::borrow_tracker::RetagFields; use crate::diagnostics::report_leaks; @@ -304,7 +305,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( for arg in config.args.iter() { // Make space for `0` terminator. let size = u64::try_from(arg.len()).unwrap().checked_add(1).unwrap(); - let arg_type = tcx.mk_array(tcx.types.u8, size); + let arg_type = Ty::new_array(tcx,tcx.types.u8, size); let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into())?; ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?; @@ -313,7 +314,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } // Make an array with all these pointers, in the Miri memory. let argvs_layout = ecx.layout_of( - tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), u64::try_from(argvs.len()).unwrap()), + Ty::new_array(tcx,Ty::new_imm_ptr(tcx,tcx.types.u8), u64::try_from(argvs.len()).unwrap()), )?; let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into())?; for (idx, arg) in argvs.into_iter().enumerate() { @@ -332,7 +333,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.machine.argc = Some(*argc_place); let argv_place = ecx.allocate( - ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?, + ecx.layout_of(Ty::new_imm_ptr(tcx,tcx.types.unit))?, MiriMemoryKind::Machine.into(), )?; ecx.write_immediate(argv, &argv_place.into())?; @@ -344,7 +345,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Construct a command string with all the arguments. let cmd_utf16: Vec<u16> = args_to_utf16_command_string(config.args.iter()); - let cmd_type = tcx.mk_array(tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap()); + let cmd_type = Ty::new_array(tcx,tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap()); let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into())?; ecx.machine.cmd_line = Some(*cmd_place); diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index bbe5bbee719..5fcf3905199 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -313,10 +313,10 @@ pub struct PrimitiveLayouts<'tcx> { impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result<Self, &'tcx LayoutError<'tcx>> { let tcx = layout_cx.tcx; - let mut_raw_ptr = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut }); - let const_raw_ptr = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not }); + let mut_raw_ptr = Ty::new_ptr(tcx,TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut }); + let const_raw_ptr = Ty::new_ptr(tcx,TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not }); Ok(Self { - unit: layout_cx.layout_of(tcx.mk_unit())?, + unit: layout_cx.layout_of(Ty::new_unit(tcx,))?, i8: layout_cx.layout_of(tcx.types.i8)?, i16: layout_cx.layout_of(tcx.types.i16)?, i32: layout_cx.layout_of(tcx.types.i32)?, diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index 323991249d3..eaa66f1f874 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -1,7 +1,7 @@ use crate::*; use rustc_ast::ast::Mutability; use rustc_middle::ty::layout::LayoutOf as _; -use rustc_middle::ty::{self, Instance}; +use rustc_middle::ty::{self, Instance, Ty}; use rustc_span::{BytePos, Loc, Symbol}; use rustc_target::{abi::Size, spec::abi::Abi}; @@ -71,7 +71,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let len: u64 = ptrs.len().try_into().unwrap(); let ptr_ty = this.machine.layouts.mut_raw_ptr.ty; - let array_layout = this.layout_of(tcx.mk_array(ptr_ty, len)).unwrap(); + let array_layout = this.layout_of(Ty::new_array(tcx.tcx,ptr_ty, len)).unwrap(); match flags { // storage for pointers is allocated by miri diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs index f50c135435f..3d4967f1f83 100644 --- a/src/tools/miri/src/shims/env.rs +++ b/src/tools/miri/src/shims/env.rs @@ -5,6 +5,7 @@ use std::mem; use rustc_const_eval::interpret::Pointer; use rustc_data_structures::fx::FxHashMap; +use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf; use rustc_target::abi::Size; @@ -449,7 +450,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Make an array with all these pointers inside Miri. let tcx = this.tcx; let vars_layout = this.layout_of( - tcx.mk_array(this.machine.layouts.mut_raw_ptr.ty, u64::try_from(vars.len()).unwrap()), + Ty::new_array(tcx.tcx,this.machine.layouts.mut_raw_ptr.ty, u64::try_from(vars.len()).unwrap()), )?; let vars_place = this.allocate(vars_layout, MiriMemoryKind::Runtime.into())?; for (idx, var) in vars.into_iter().enumerate() { diff --git a/src/tools/miri/src/shims/os_str.rs b/src/tools/miri/src/shims/os_str.rs index e85ab7a48b3..4cdd54fa21b 100644 --- a/src/tools/miri/src/shims/os_str.rs +++ b/src/tools/miri/src/shims/os_str.rs @@ -7,6 +7,7 @@ use std::os::unix::ffi::{OsStrExt, OsStringExt}; #[cfg(windows)] use std::os::windows::ffi::{OsStrExt, OsStringExt}; +use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf; use crate::*; @@ -140,7 +141,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator. let this = self.eval_context_mut(); - let arg_type = this.tcx.mk_array(this.tcx.types.u8, size); + let arg_type = Ty::new_array(this.tcx.tcx,this.tcx.types.u8, size); let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; let (written, _) = self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap(); assert!(written); @@ -156,7 +157,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator. let this = self.eval_context_mut(); - let arg_type = this.tcx.mk_array(this.tcx.types.u16, size); + let arg_type = Ty::new_array(this.tcx.tcx,this.tcx.types.u16, size); let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; let (written, _) = self.write_os_str_to_wide_str(os_str, arg_place.ptr, size, /*truncate*/ false).unwrap(); diff --git a/src/tools/rust-installer/install-template.sh b/src/tools/rust-installer/install-template.sh index 92a3f1f2c98..6415644e045 100644 --- a/src/tools/rust-installer/install-template.sh +++ b/src/tools/rust-installer/install-template.sh @@ -17,8 +17,8 @@ log_line() { local _line="$1" if [ -n "${LOGFILE-}" -a -e "${LOGFILE-}" ]; then - echo "$_line" >> "$LOGFILE" - # Ignore errors, which may happen e.g. after the manifest dir is deleted + echo "$_line" >> "$LOGFILE" + # Ignore errors, which may happen e.g. after the manifest dir is deleted fi } @@ -30,9 +30,9 @@ msg() { verbose_msg() { if [ -n "${CFG_VERBOSE-}" ]; then - msg "${1-}" + msg "${1-}" else - log_line "install: ${1-}" + log_line "install: ${1-}" fi } @@ -44,13 +44,13 @@ step_msg() { verbose_step_msg() { if [ -n "${CFG_VERBOSE-}" ]; then - msg - msg "$1" - msg + msg + msg "$1" + msg else - log_line "" - log_line "install: $1" - log_line "" + log_line "" + log_line "install: $1" + log_line "" fi } @@ -91,7 +91,7 @@ critical_need_ok() { want_ok() { if [ $? -ne 0 ]; then - warn "$1" + warn "$1" fi } @@ -321,40 +321,40 @@ uninstall_legacy() { # Uninstall from legacy manifests local _md for _md in $_legacy_manifest_dirs; do - # First, uninstall from the installation prefix. - # Errors are warnings - try to rm everything in the manifest even if some fail. - if [ -f "$_abs_libdir/$_md/manifest" ] - then - - # iterate through installed manifest and remove files - local _p; - while read _p; do - # the installed manifest contains absolute paths - msg "removing legacy file $_p" - if [ -f "$_p" ] - then - run rm -f "$_p" - want_ok "failed to remove $_p" - else - warn "supposedly installed file $_p does not exist!" - fi - done < "$_abs_libdir/$_md/manifest" - - # If we fail to remove $md below, then the - # installed manifest will still be full; the installed manifest - # needs to be empty before install. - msg "removing legacy manifest $_abs_libdir/$_md/manifest" - run rm -f "$_abs_libdir/$_md/manifest" - # For the above reason, this is a hard error - need_ok "failed to remove installed manifest" - - # Remove $template_rel_manifest_dir directory - msg "removing legacy manifest dir $_abs_libdir/$_md" - run rm -R "$_abs_libdir/$_md" - want_ok "failed to remove $_md" - - _uninstalled_something=true - fi + # First, uninstall from the installation prefix. + # Errors are warnings - try to rm everything in the manifest even if some fail. + if [ -f "$_abs_libdir/$_md/manifest" ] + then + + # iterate through installed manifest and remove files + local _p; + while read _p; do + # the installed manifest contains absolute paths + msg "removing legacy file $_p" + if [ -f "$_p" ] + then + run rm -f "$_p" + want_ok "failed to remove $_p" + else + warn "supposedly installed file $_p does not exist!" + fi + done < "$_abs_libdir/$_md/manifest" + + # If we fail to remove $md below, then the + # installed manifest will still be full; the installed manifest + # needs to be empty before install. + msg "removing legacy manifest $_abs_libdir/$_md/manifest" + run rm -f "$_abs_libdir/$_md/manifest" + # For the above reason, this is a hard error + need_ok "failed to remove installed manifest" + + # Remove $template_rel_manifest_dir directory + msg "removing legacy manifest dir $_abs_libdir/$_md" + run rm -R "$_abs_libdir/$_md" + want_ok "failed to remove $_md" + + _uninstalled_something=true + fi done RETVAL="$_uninstalled_something" @@ -373,133 +373,134 @@ uninstall_components() { uninstall_legacy "$_abs_libdir" assert_nz "$RETVAL", "RETVAL" if [ "$RETVAL" = true ]; then - _uninstalled_something=true; + _uninstalled_something=true; fi # Load the version of the installed installer local _installed_version= if [ -f "$abs_libdir/$TEMPLATE_REL_MANIFEST_DIR/rust-installer-version" ]; then - _installed_version=`cat "$_abs_libdir/$TEMPLATE_REL_MANIFEST_DIR/rust-installer-version"` + _installed_version=`cat "$_abs_libdir/$TEMPLATE_REL_MANIFEST_DIR/rust-installer-version"` - # Sanity check - if [ ! -n "$_installed_version" ]; then critical_err "rust installer version is empty"; fi + # Sanity check + if [ ! -n "$_installed_version" ]; then critical_err "rust installer version is empty"; fi fi # If there's something installed, then uninstall if [ -n "$_installed_version" ]; then - # Check the version of the installed installer - case "$_installed_version" in - - # If this is a previous version, then upgrade in place to the - # current version before uninstalling. - 2 ) - # The only change between version 2 -> 3 is that components are placed - # in subdirectories of the installer tarball. There are no changes - # to the installed data format, so nothing to do. - ;; - - # This is the current version. Nothing need to be done except uninstall. - "$TEMPLATE_RUST_INSTALLER_VERSION") - ;; - - # If this is an unknown (future) version then bail. - * ) - echo "The copy of $TEMPLATE_PRODUCT_NAME at $_dest_prefix was installed using an" - echo "unknown version ($_installed_version) of rust-installer." - echo "Uninstall it first with the installer used for the original installation" - echo "before continuing." - exit 1 - ;; - esac - - local _md="$_abs_libdir/$TEMPLATE_REL_MANIFEST_DIR" - local _installed_components="$(cat "$_md/components")" - - # Uninstall (our components only) before reinstalling - local _available_component - for _available_component in $_components; do - local _installed_component - for _installed_component in $_installed_components; do - if [ "$_available_component" = "$_installed_component" ]; then - msg "uninstalling component '$_available_component'" - local _component_manifest="$_md/manifest-$_installed_component" - - # Sanity check: there should be a component manifest - if [ ! -f "$_component_manifest" ]; then - critical_err "installed component '$_installed_component' has no manifest" - fi - - # Iterate through installed component manifest and remove files - local _directive - while read _directive; do - - local _command=`echo $_directive | cut -f1 -d:` - local _file=`echo $_directive | cut -f2 -d:` - - # Sanity checks - if [ ! -n "$_command" ]; then critical_err "malformed installation directive"; fi - if [ ! -n "$_file" ]; then critical_err "malformed installation directive"; fi - - case "$_command" in - file) - verbose_msg "removing file $_file" - if [ -f "$_file" ]; then - run rm -f "$_file" - want_ok "failed to remove $_file" - else - warn "supposedly installed file $_file does not exist!" - fi - ;; - - dir) - verbose_msg "removing directory $_file" - run rm -r "$_file" - want_ok "unable to remove directory $_file" - ;; - - *) - critical_err "unknown installation directive" - ;; - esac - - done < "$_component_manifest" - - # Remove the installed component manifest - verbose_msg "removing component manifest $_component_manifest" - run rm "$_component_manifest" - # This is a hard error because the installation is unrecoverable - critical_need_ok "failed to remove installed manifest for component '$_installed_component'" - - # Update the installed component list - local _modified_components="$(sed "/^$_installed_component\$/d" "$_md/components")" - write_to_file "$_modified_components" "$_md/components" - critical_need_ok "failed to update installed component list" - fi - done - done - - # If there are no remaining components delete the manifest directory, - # but only if we're doing an uninstall - if we're doing an install, - # then leave the manifest directory around to hang onto the logs, - # and any files not managed by the installer. - if [ -n "${CFG_UNINSTALL-}" ]; then - local _remaining_components="$(cat "$_md/components")" - if [ ! -n "$_remaining_components" ]; then - verbose_msg "removing manifest directory $_md" - run rm -r "$_md" - want_ok "failed to remove $_md" - - maybe_unconfigure_ld - fi - fi - - _uninstalled_something=true + # Check the version of the installed installer + case "$_installed_version" in + + # If this is a previous version, then upgrade in place to the + # current version before uninstalling. + 2 ) + # The only change between version 2 -> 3 is that components are placed + # in subdirectories of the installer tarball. There are no changes + # to the installed data format, so nothing to do. + ;; + + # This is the current version. Nothing need to be done except uninstall. + "$TEMPLATE_RUST_INSTALLER_VERSION") + ;; + + # If this is an unknown (future) version then bail. + * ) + echo "The copy of $TEMPLATE_PRODUCT_NAME at $_dest_prefix was installed using an" + echo "unknown version ($_installed_version) of rust-installer." + echo "Uninstall it first with the installer used for the original installation" + echo "before continuing." + exit 1 + ;; + esac + + local _md="$_abs_libdir/$TEMPLATE_REL_MANIFEST_DIR" + local _installed_components="$(cat "$_md/components")" + + # Uninstall (our components only) before reinstalling + local _available_component + for _available_component in $_components; do + local _installed_component + for _installed_component in $_installed_components; do + if [ "$_available_component" = "$_installed_component" ]; then + msg "uninstalling component '$_available_component'" + local _component_manifest="$_md/manifest-$_installed_component" + + # Sanity check: there should be a component manifest + if [ ! -f "$_component_manifest" ]; then + critical_err "installed component '$_installed_component' has no manifest" + fi + + # Iterate through installed component manifest and remove files + local _directive + while read _directive; do + + local _command=`echo $_directive | cut -f1 -d:` + local _file=`echo $_directive | cut -f2 -d:` + + # Sanity checks + if [ ! -n "$_command" ]; then critical_err "malformed installation directive"; fi + if [ ! -n "$_file" ]; then critical_err "malformed installation directive"; fi + + case "$_command" in + file) + verbose_msg "removing file $_file" + if [ -f "$_file" ]; then + run rm -f "$_file" + want_ok "failed to remove $_file" + else + warn "supposedly installed file $_file does not exist!" + fi + ;; + + dir) + verbose_msg "removing directory $_file" + run rm -r "$_file" + want_ok "unable to remove directory $_file" + ;; + + *) + critical_err "unknown installation directive" + ;; + esac + + done < "$_component_manifest" + + # Remove the installed component manifest + verbose_msg "removing component manifest $_component_manifest" + run rm "$_component_manifest" + # This is a hard error because the installation is unrecoverable + local _err_cant_r_manifest="failed to remove installed manifest for component" + critical_need_ok "$_err_cant_r_manifest '$_installed_component'" + + # Update the installed component list + local _modified_components="$(sed "/^$_installed_component\$/d" "$_md/components")" + write_to_file "$_modified_components" "$_md/components" + critical_need_ok "failed to update installed component list" + fi + done + done + + # If there are no remaining components delete the manifest directory, + # but only if we're doing an uninstall - if we're doing an install, + # then leave the manifest directory around to hang onto the logs, + # and any files not managed by the installer. + if [ -n "${CFG_UNINSTALL-}" ]; then + local _remaining_components="$(cat "$_md/components")" + if [ ! -n "$_remaining_components" ]; then + verbose_msg "removing manifest directory $_md" + run rm -r "$_md" + want_ok "failed to remove $_md" + + maybe_unconfigure_ld + fi + fi + + _uninstalled_something=true fi # There's no installed version. If we were asked to uninstall, then that's a problem. if [ -n "${CFG_UNINSTALL-}" -a "$_uninstalled_something" = false ] then - err "unable to find installation manifest at $CFG_LIBDIR/$TEMPLATE_REL_MANIFEST_DIR" + err "unable to find installation manifest at $CFG_LIBDIR/$TEMPLATE_REL_MANIFEST_DIR" fi } @@ -512,73 +513,73 @@ install_components() { local _component for _component in $_components; do - msg "installing component '$_component'" + msg "installing component '$_component'" - # The file name of the manifest we're installing from - local _input_manifest="$_src_dir/$_component/manifest.in" + # The file name of the manifest we're installing from + local _input_manifest="$_src_dir/$_component/manifest.in" - # Sanity check: do we have our input manifests? - if [ ! -f "$_input_manifest" ]; then - critical_err "manifest for $_component does not exist at $_input_manifest" - fi + # Sanity check: do we have our input manifests? + if [ ! -f "$_input_manifest" ]; then + critical_err "manifest for $_component does not exist at $_input_manifest" + fi - # The installed manifest directory - local _md="$_abs_libdir/$TEMPLATE_REL_MANIFEST_DIR" + # The installed manifest directory + local _md="$_abs_libdir/$TEMPLATE_REL_MANIFEST_DIR" - # The file name of the manifest we're going to create during install - local _installed_manifest="$_md/manifest-$_component" + # The file name of the manifest we're going to create during install + local _installed_manifest="$_md/manifest-$_component" - # Create the installed manifest, which we will fill in with absolute file paths - touch "$_installed_manifest" - critical_need_ok "failed to create installed manifest" + # Create the installed manifest, which we will fill in with absolute file paths + touch "$_installed_manifest" + critical_need_ok "failed to create installed manifest" - # Add this component to the installed component list - append_to_file "$_component" "$_md/components" - critical_need_ok "failed to update components list for $_component" + # Add this component to the installed component list + append_to_file "$_component" "$_md/components" + critical_need_ok "failed to update components list for $_component" - # Now install, iterate through the new manifest and copy files - local _directive - while read _directive; do + # Now install, iterate through the new manifest and copy files + local _directive + while read _directive; do - local _command=`echo $_directive | cut -f1 -d:` - local _file=`echo $_directive | cut -f2 -d:` + local _command=`echo $_directive | cut -f1 -d:` + local _file=`echo $_directive | cut -f2 -d:` - # Sanity checks - if [ ! -n "$_command" ]; then critical_err "malformed installation directive"; fi - if [ ! -n "$_file" ]; then critical_err "malformed installation directive"; fi + # Sanity checks + if [ ! -n "$_command" ]; then critical_err "malformed installation directive"; fi + if [ ! -n "$_file" ]; then critical_err "malformed installation directive"; fi - # Decide the destination of the file - local _file_install_path="$_dest_prefix/$_file" + # Decide the destination of the file + local _file_install_path="$_dest_prefix/$_file" - if echo "$_file" | grep "^etc/" > /dev/null - then - local _f="$(echo "$_file" | sed 's/^etc\///')" - _file_install_path="$CFG_SYSCONFDIR/$_f" - fi + if echo "$_file" | grep "^etc/" > /dev/null + then + local _f="$(echo "$_file" | sed 's/^etc\///')" + _file_install_path="$CFG_SYSCONFDIR/$_f" + fi - if echo "$_file" | grep "^bin/" > /dev/null - then - local _f="$(echo "$_file" | sed 's/^bin\///')" - _file_install_path="$CFG_BINDIR/$_f" - fi + if echo "$_file" | grep "^bin/" > /dev/null + then + local _f="$(echo "$_file" | sed 's/^bin\///')" + _file_install_path="$CFG_BINDIR/$_f" + fi - if echo "$_file" | grep "^lib/" > /dev/null - then - local _f="$(echo "$_file" | sed 's/^lib\///')" - _file_install_path="$CFG_LIBDIR/$_f" - fi + if echo "$_file" | grep "^lib/" > /dev/null + then + local _f="$(echo "$_file" | sed 's/^lib\///')" + _file_install_path="$CFG_LIBDIR/$_f" + fi - if echo "$_file" | grep "^share" > /dev/null - then - local _f="$(echo "$_file" | sed 's/^share\///')" - _file_install_path="$CFG_DATADIR/$_f" - fi + if echo "$_file" | grep "^share" > /dev/null + then + local _f="$(echo "$_file" | sed 's/^share\///')" + _file_install_path="$CFG_DATADIR/$_f" + fi - if echo "$_file" | grep "^share/man/" > /dev/null - then - local _f="$(echo "$_file" | sed 's/^share\/man\///')" - _file_install_path="$CFG_MANDIR/$_f" - fi + if echo "$_file" | grep "^share/man/" > /dev/null + then + local _f="$(echo "$_file" | sed 's/^share\/man\///')" + _file_install_path="$CFG_MANDIR/$_f" + fi # HACK: Try to support overriding --docdir. Paths with the form # "share/doc/$product/" can be redirected to a single --docdir @@ -592,69 +593,69 @@ install_components() { # this problem to be a big deal in practice. if [ "$CFG_DOCDIR" != "<default>" ] then - if echo "$_file" | grep "^share/doc/" > /dev/null - then - local _f="$(echo "$_file" | sed 's/^share\/doc\/[^/]*\///')" - _file_install_path="$CFG_DOCDIR/$_f" - fi + if echo "$_file" | grep "^share/doc/" > /dev/null + then + local _f="$(echo "$_file" | sed 's/^share\/doc\/[^/]*\///')" + _file_install_path="$CFG_DOCDIR/$_f" + fi fi - # Make sure there's a directory for it - make_dir_recursive "$(dirname "$_file_install_path")" - critical_need_ok "directory creation failed" + # Make sure there's a directory for it + make_dir_recursive "$(dirname "$_file_install_path")" + critical_need_ok "directory creation failed" - # Make the path absolute so we can uninstall it later without - # starting from the installation cwd - absolutify "$_file_install_path" - _file_install_path="$RETVAL" - assert_nz "$_file_install_path" "file_install_path" + # Make the path absolute so we can uninstall it later without + # starting from the installation cwd + absolutify "$_file_install_path" + _file_install_path="$RETVAL" + assert_nz "$_file_install_path" "file_install_path" - case "$_command" in - file ) + case "$_command" in + file ) - verbose_msg "copying file $_file_install_path" + verbose_msg "copying file $_file_install_path" - maybe_backup_path "$_file_install_path" + maybe_backup_path "$_file_install_path" - if echo "$_file" | grep "^bin/" > /dev/null || test -x "$_src_dir/$_component/$_file" - then - run cp "$_src_dir/$_component/$_file" "$_file_install_path" - run chmod 755 "$_file_install_path" - else - run cp "$_src_dir/$_component/$_file" "$_file_install_path" - run chmod 644 "$_file_install_path" - fi - critical_need_ok "file creation failed" + if echo "$_file" | grep "^bin/" > /dev/null || test -x "$_src_dir/$_component/$_file" + then + run cp "$_src_dir/$_component/$_file" "$_file_install_path" + run chmod 755 "$_file_install_path" + else + run cp "$_src_dir/$_component/$_file" "$_file_install_path" + run chmod 644 "$_file_install_path" + fi + critical_need_ok "file creation failed" - # Update the manifest - append_to_file "file:$_file_install_path" "$_installed_manifest" - critical_need_ok "failed to update manifest" + # Update the manifest + append_to_file "file:$_file_install_path" "$_installed_manifest" + critical_need_ok "failed to update manifest" - ;; + ;; - dir ) + dir ) - verbose_msg "copying directory $_file_install_path" + verbose_msg "copying directory $_file_install_path" - maybe_backup_path "$_file_install_path" + maybe_backup_path "$_file_install_path" - run cp -R "$_src_dir/$_component/$_file" "$_file_install_path" - critical_need_ok "failed to copy directory" + run cp -R "$_src_dir/$_component/$_file" "$_file_install_path" + critical_need_ok "failed to copy directory" # Set permissions. 0755 for dirs, 644 for files run chmod -R u+rwX,go+rX,go-w "$_file_install_path" critical_need_ok "failed to set permissions on directory" - # Update the manifest - append_to_file "dir:$_file_install_path" "$_installed_manifest" - critical_need_ok "failed to update manifest" - ;; + # Update the manifest + append_to_file "dir:$_file_install_path" "$_installed_manifest" + critical_need_ok "failed to update manifest" + ;; - *) - critical_err "unknown installation directive" - ;; - esac - done < "$_input_manifest" + *) + critical_err "unknown installation directive" + ;; + esac + done < "$_input_manifest" done } @@ -667,33 +668,35 @@ maybe_configure_ld() { if [ "$_ostype" = "Linux" -a ! -n "${CFG_DISABLE_LDCONFIG-}" ]; then - # Fedora-based systems do not configure the dynamic linker to look - # /usr/local/lib, which is our default installation directory. To - # make things just work, try to put that directory in - # /etc/ld.so.conf.d/rust-installer-v1 so ldconfig picks it up. - # Issue #30. - # - # This will get rm'd when the last component is uninstalled in - # maybe_unconfigure_ld. - if [ "$_abs_libdir" = "/usr/local/lib" -a -d "/etc/ld.so.conf.d" ]; then - echo "$_abs_libdir" > "/etc/ld.so.conf.d/rust-installer-v1-$TEMPLATE_REL_MANIFEST_DIR.conf" - if [ $? -ne 0 ]; then - # This shouldn't happen if we've gotten this far - # installing to /usr/local - warn "failed to update /etc/ld.so.conf.d. this is unexpected" - fi - fi - - verbose_msg "running ldconfig" - if [ -n "${CFG_VERBOSE-}" ]; then - ldconfig - else - ldconfig 2> /dev/null - fi - if [ $? -ne 0 ] - then - warn "failed to run ldconfig. this may happen when not installing as root. run with --verbose to see the error" - fi + # Fedora-based systems do not configure the dynamic linker to look + # /usr/local/lib, which is our default installation directory. To + # make things just work, try to put that directory in + # /etc/ld.so.conf.d/rust-installer-v1 so ldconfig picks it up. + # Issue #30. + # + # This will get rm'd when the last component is uninstalled in + # maybe_unconfigure_ld. + if [ "$_abs_libdir" = "/usr/local/lib" -a -d "/etc/ld.so.conf.d" ]; then + echo "$_abs_libdir" > "/etc/ld.so.conf.d/rust-installer-v1-$TEMPLATE_REL_MANIFEST_DIR.conf" + if [ $? -ne 0 ]; then + # This shouldn't happen if we've gotten this far + # installing to /usr/local + warn "failed to update /etc/ld.so.conf.d. this is unexpected" + fi + fi + + verbose_msg "running ldconfig" + if [ -n "${CFG_VERBOSE-}" ]; then + ldconfig + else + ldconfig 2> /dev/null + fi + if [ $? -ne 0 ] + then + local _warn_s="failed to run ldconfig. this may happen when \ +not installing as root. run with --verbose to see the error" + warn "$_warn_s" + fi fi } @@ -702,7 +705,7 @@ maybe_unconfigure_ld() { assert_nz "$_ostype" "ostype" if [ "$_ostype" != "Linux" ]; then - return 0 + return 0 fi rm "/etc/ld.so.conf.d/rust-installer-v1-$TEMPLATE_REL_MANIFEST_DIR.conf" 2> /dev/null @@ -714,9 +717,9 @@ maybe_backup_path() { local _file_install_path="$1" if [ -e "$_file_install_path" ]; then - msg "backing up existing file at $_file_install_path" - run mv -f "$_file_install_path" "$_file_install_path.old" - critical_need_ok "failed to back up $_file_install_path" + msg "backing up existing file at $_file_install_path" + run mv -f "$_file_install_path" "$_file_install_path.old" + critical_need_ok "failed to back up $_file_install_path" fi } @@ -742,7 +745,7 @@ do_preflight_sanity_checks() { touch "$CFG_LIBDIR/rust-install-probe" > /dev/null if [ $? -ne 0 ] then - err "can't write to destination. consider \`sudo\`." + err "can't write to destination. consider \`sudo\`." fi rm "$CFG_LIBDIR/rust-install-probe" need_ok "failed to remove install probe" @@ -752,7 +755,7 @@ do_preflight_sanity_checks() { verbose_msg "verifying destination is not the same as source" local _prefix_dir="$(abs_path "$dest_prefix")" if [ "$_src_dir" = "$_dest_prefix" -a "${CFG_UNINSTALL-}" != 1 ]; then - err "cannot install to same directory as installer" + err "cannot install to same directory as installer" fi } @@ -857,8 +860,8 @@ src_basename="$(basename "$0")" # which just means 'uninstall my components'. if [ "$src_basename" = "uninstall.sh" ]; then if [ "${*:-}" != "" ]; then - # Currently don't know what to do with arguments in this mode - err "uninstall.sh does not take any arguments" + # Currently don't know what to do with arguments in this mode + err "uninstall.sh does not take any arguments" fi CFG_UNINSTALL=1 CFG_DESTDIR_PREFIX="$(abs_path "$src_dir/../../")" @@ -885,7 +888,7 @@ if [ -n "${CFG_LIST_COMPONENTS-}" ]; then echo "# Available components" echo for component in $components; do - echo "* $component" + echo "* $component" done echo exit 0 @@ -897,15 +900,15 @@ if [ -n "$CFG_COMPONENTS" ]; then # Remove commas user_components="$(echo "$CFG_COMPONENTS" | sed "s/,/ /g")" for user_component in $user_components; do - found=false - for my_component in $components; do - if [ "$user_component" = "$my_component" ]; then - found=true - fi - done - if [ "$found" = false ]; then - err "unknown component: $user_component" - fi + found=false + for my_component in $components; do + if [ "$user_component" = "$my_component" ]; then + found=true + fi + done + if [ "$found" = false ]; then + err "unknown component: $user_component" + fi done components="$user_components" fi @@ -937,9 +940,9 @@ fi if [ -z "$components" ]; then if [ -z "${CFG_UNINSTALL-}" ]; then - err "no components selected for installation" + err "no components selected for installation" else - err "no components selected for uninstallation" + err "no components selected for uninstallation" fi fi @@ -977,7 +980,9 @@ make_dir_recursive "$abs_libdir/$TEMPLATE_REL_MANIFEST_DIR" need_ok "failed to create $TEMPLATE_REL_MANIFEST_DIR" # Drop the version number into the manifest dir -write_to_file "$TEMPLATE_RUST_INSTALLER_VERSION" "$abs_libdir/$TEMPLATE_REL_MANIFEST_DIR/rust-installer-version" +write_to_file "$TEMPLATE_RUST_INSTALLER_VERSION" \ +"$abs_libdir/$TEMPLATE_REL_MANIFEST_DIR/rust-installer-version" + critical_need_ok "failed to write installer version" # Install the uninstaller @@ -992,5 +997,3 @@ maybe_configure_ld "$abs_libdir" echo echo " $TEMPLATE_SUCCESS_MESSAGE" echo - - diff --git a/src/tools/rust-installer/src/combiner.rs b/src/tools/rust-installer/src/combiner.rs index 19466f63fed..565d19d863f 100644 --- a/src/tools/rust-installer/src/combiner.rs +++ b/src/tools/rust-installer/src/combiner.rs @@ -71,25 +71,16 @@ impl Combiner { // Merge each installer into the work directory of the new installer. let components = create_new_file(package_dir.join("components"))?; - for input_tarball in self - .input_tarballs - .split(',') - .map(str::trim) - .filter(|s| !s.is_empty()) + for input_tarball in self.input_tarballs.split(',').map(str::trim).filter(|s| !s.is_empty()) { // Extract the input tarballs let compression = CompressionFormat::detect_from_path(input_tarball).ok_or_else(|| { anyhow::anyhow!("couldn't figure out the format of {}", input_tarball) })?; - Archive::new(compression.decode(input_tarball)?) - .unpack(&self.work_dir) - .with_context(|| { - format!( - "unable to extract '{}' into '{}'", - &input_tarball, self.work_dir - ) - })?; + Archive::new(compression.decode(input_tarball)?).unpack(&self.work_dir).with_context( + || format!("unable to extract '{}' into '{}'", &input_tarball, self.work_dir), + )?; let pkg_name = input_tarball.trim_end_matches(&format!(".tar.{}", compression.extension())); @@ -126,12 +117,8 @@ impl Combiner { // Write the installer version. let version = package_dir.join("rust-installer-version"); - writeln!( - create_new_file(version)?, - "{}", - crate::RUST_INSTALLER_VERSION - ) - .context("failed to write new installer version")?; + writeln!(create_new_file(version)?, "{}", crate::RUST_INSTALLER_VERSION) + .context("failed to write new installer version")?; // Copy the overlay. if !self.non_installed_overlay.is_empty() { diff --git a/src/tools/rust-installer/src/generator.rs b/src/tools/rust-installer/src/generator.rs index 45f8c49d03e..b101e67d8df 100644 --- a/src/tools/rust-installer/src/generator.rs +++ b/src/tools/rust-installer/src/generator.rs @@ -86,12 +86,8 @@ impl Generator { // Write the installer version (only used by combine-installers.sh) let version = package_dir.join("rust-installer-version"); - writeln!( - create_new_file(version)?, - "{}", - crate::RUST_INSTALLER_VERSION - ) - .context("failed to write new installer version")?; + writeln!(create_new_file(version)?, "{}", crate::RUST_INSTALLER_VERSION) + .context("failed to write new installer version")?; // Copy the overlay if !self.non_installed_overlay.is_empty() { @@ -128,33 +124,19 @@ impl Generator { /// Copies the `src` directory recursively to `dst`, writing `manifest.in` too. fn copy_and_manifest(src: &Path, dst: &Path, bulk_dirs: &str) -> Result<()> { let mut manifest = create_new_file(dst.join("manifest.in"))?; - let bulk_dirs: Vec<_> = bulk_dirs - .split(',') - .filter(|s| !s.is_empty()) - .map(Path::new) - .collect(); + let bulk_dirs: Vec<_> = bulk_dirs.split(',').filter(|s| !s.is_empty()).map(Path::new).collect(); let mut paths = BTreeSet::new(); copy_with_callback(src, dst, |path, file_type| { // We need paths to be compatible with both Unix and Windows. - if path - .components() - .filter_map(|c| c.as_os_str().to_str()) - .any(|s| s.contains('\\')) - { - bail!( - "rust-installer doesn't support '\\' in path components: {:?}", - path - ); + if path.components().filter_map(|c| c.as_os_str().to_str()).any(|s| s.contains('\\')) { + bail!("rust-installer doesn't support '\\' in path components: {:?}", path); } // Normalize to Unix-style path separators. let normalized_string; let mut string = path.to_str().ok_or_else(|| { - format_err!( - "rust-installer doesn't support non-Unicode paths: {:?}", - path - ) + format_err!("rust-installer doesn't support non-Unicode paths: {:?}", path) })?; if string.contains('\\') { normalized_string = string.replace('\\', "/"); diff --git a/src/tools/rust-installer/src/main.rs b/src/tools/rust-installer/src/main.rs index be8a0d68343..99acecdd43c 100644 --- a/src/tools/rust-installer/src/main.rs +++ b/src/tools/rust-installer/src/main.rs @@ -19,8 +19,12 @@ fn main() -> Result<()> { let command_line = CommandLine::parse(); match command_line.command { Subcommand::Combine(combiner) => combiner.run().context("failed to combine installers")?, - Subcommand::Generate(generator) => generator.run().context("failed to generate installer")?, - Subcommand::Script(scripter) => scripter.run().context("failed to generate installation script")?, + Subcommand::Generate(generator) => { + generator.run().context("failed to generate installer")? + } + Subcommand::Script(scripter) => { + scripter.run().context("failed to generate installation script")? + } Subcommand::Tarball(tarballer) => tarballer.run().context("failed to generate tarballs")?, } Ok(()) diff --git a/src/tools/rust-installer/src/scripter.rs b/src/tools/rust-installer/src/scripter.rs index 8180f925cb0..ff65e818b09 100644 --- a/src/tools/rust-installer/src/scripter.rs +++ b/src/tools/rust-installer/src/scripter.rs @@ -32,22 +32,19 @@ actor! { impl Scripter { /// Generates the actual installer script pub fn run(self) -> Result<()> { - // Replace dashes in the success message with spaces (our arg handling botches spaces) - // TODO: still needed? Kept for compatibility for now. + // Replace dashes in the product name with spaces (our arg handling botches spaces) + // FIXME: still needed? Kept for compatibility for now. let product_name = self.product_name.replace('-', " "); // Replace dashes in the success message with spaces (our arg handling botches spaces) - // TODO: still needed? Kept for compatibility for now. + // FIXME: still needed? Kept for compatibility for now. let success_message = self.success_message.replace('-', " "); let script = TEMPLATE .replace("%%TEMPLATE_PRODUCT_NAME%%", &sh_quote(&product_name)) .replace("%%TEMPLATE_REL_MANIFEST_DIR%%", &self.rel_manifest_dir) .replace("%%TEMPLATE_SUCCESS_MESSAGE%%", &sh_quote(&success_message)) - .replace( - "%%TEMPLATE_LEGACY_MANIFEST_DIRS%%", - &sh_quote(&self.legacy_manifest_dirs), - ) + .replace("%%TEMPLATE_LEGACY_MANIFEST_DIRS%%", &sh_quote(&self.legacy_manifest_dirs)) .replace( "%%TEMPLATE_RUST_INSTALLER_VERSION%%", &sh_quote(&crate::RUST_INSTALLER_VERSION), diff --git a/src/tools/rust-installer/src/tarballer.rs b/src/tools/rust-installer/src/tarballer.rs index c60d5f648ff..7572dc6dcf8 100644 --- a/src/tools/rust-installer/src/tarballer.rs +++ b/src/tools/rust-installer/src/tarballer.rs @@ -58,10 +58,7 @@ impl Tarballer { let buf = BufWriter::with_capacity(1024 * 1024, encoder); let mut builder = Builder::new(buf); - let pool = rayon::ThreadPoolBuilder::new() - .num_threads(2) - .build() - .unwrap(); + let pool = rayon::ThreadPoolBuilder::new().num_threads(2).build().unwrap(); pool.install(move || { for path in dirs { let src = Path::new(&self.work_dir).join(&path); @@ -122,11 +119,7 @@ where let name = name.as_ref(); if !name.is_relative() && !name.starts_with(root) { - bail!( - "input '{}' is not in work dir '{}'", - name.display(), - root.display() - ); + bail!("input '{}' is not in work dir '{}'", name.display(), root.display()); } let mut dirs = vec![]; diff --git a/src/tools/rust-installer/src/util.rs b/src/tools/rust-installer/src/util.rs index 4eb2e75fd7e..47ca0cfa3cc 100644 --- a/src/tools/rust-installer/src/util.rs +++ b/src/tools/rust-installer/src/util.rs @@ -15,8 +15,7 @@ use std::os::windows::fs::symlink_file; /// Converts a `&Path` to a UTF-8 `&str`. pub fn path_to_str(path: &Path) -> Result<&str> { - path.to_str() - .ok_or_else(|| format_err!("path is not valid UTF-8 '{}'", path.display())) + path.to_str().ok_or_else(|| format_err!("path is not valid UTF-8 '{}'", path.display())) } /// Wraps `fs::copy` with a nicer error message. @@ -27,11 +26,7 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<u64> { Ok(0) } else { let amt = fs::copy(&from, &to).with_context(|| { - format!( - "failed to copy '{}' to '{}'", - from.as_ref().display(), - to.as_ref().display() - ) + format!("failed to copy '{}' to '{}'", from.as_ref().display(), to.as_ref().display()) })?; Ok(amt) } @@ -123,8 +118,12 @@ where } macro_rules! actor_field_default { - () => { Default::default() }; - (= $expr:expr) => { $expr.into() } + () => { + Default::default() + }; + (= $expr:expr) => { + $expr.into() + }; } /// Creates an "actor" with default values, setters for all fields, and Clap parser support. diff --git a/src/tools/rust-installer/test.sh b/src/tools/rust-installer/test.sh index dac6f77ef14..4f69bfc63e9 100755 --- a/src/tools/rust-installer/test.sh +++ b/src/tools/rust-installer/test.sh @@ -27,7 +27,7 @@ PREFIX_DIR="$TMP_DIR/prefix" case $(uname -s) in MINGW* | MSYS*) - WINDOWS=1 + WINDOWS=1 ;; esac @@ -48,10 +48,10 @@ pre() { need_ok() { if [ $? -ne 0 ] then - echo - echo "TEST FAILED!" - echo - exit 1 + echo + echo "TEST FAILED!" + echo + exit 1 fi } @@ -69,20 +69,20 @@ try() { _cmd="$@" _output=`$@ 2>&1` if [ $? -ne 0 ]; then - echo \$ "$_cmd" - # Using /bin/echo to avoid escaping - $ECHO "$_output" - echo - echo "TEST FAILED!" - echo - exit 1 + echo \$ "$_cmd" + # Using /bin/echo to avoid escaping + $ECHO "$_output" + echo + echo "TEST FAILED!" + echo + exit 1 else - if [ -n "${VERBOSE-}" -o -n "${VERBOSE_CMD-}" ]; then - echo \$ "$_cmd" - fi - if [ -n "${VERBOSE-}" -o -n "${VERBOSE_OUTPUT-}" ]; then - $ECHO "$_output" - fi + if [ -n "${VERBOSE-}" -o -n "${VERBOSE_CMD-}" ]; then + echo \$ "$_cmd" + fi + if [ -n "${VERBOSE-}" -o -n "${VERBOSE_OUTPUT-}" ]; then + $ECHO "$_output" + fi fi set -e } @@ -92,20 +92,20 @@ expect_fail() { _cmd="$@" _output=`$@ 2>&1` if [ $? -eq 0 ]; then - echo \$ "$_cmd" - # Using /bin/echo to avoid escaping - $ECHO "$_output" - echo - echo "TEST FAILED!" - echo - exit 1 + echo \$ "$_cmd" + # Using /bin/echo to avoid escaping + $ECHO "$_output" + echo + echo "TEST FAILED!" + echo + exit 1 else - if [ -n "${VERBOSE-}" -o -n "${VERBOSE_CMD-}" ]; then - echo \$ "$_cmd" - fi - if [ -n "${VERBOSE-}" -o -n "${VERBOSE_OUTPUT-}" ]; then - $ECHO "$_output" - fi + if [ -n "${VERBOSE-}" -o -n "${VERBOSE_CMD-}" ]; then + echo \$ "$_cmd" + fi + if [ -n "${VERBOSE-}" -o -n "${VERBOSE_OUTPUT-}" ]; then + $ECHO "$_output" + fi fi set -e } @@ -117,30 +117,30 @@ expect_output_ok() { _cmd="$@" _output=`$@ 2>&1` if [ $? -ne 0 ]; then - echo \$ "$_cmd" - # Using /bin/echo to avoid escaping - $ECHO "$_output" - echo - echo "TEST FAILED!" - echo - exit 1 + echo \$ "$_cmd" + # Using /bin/echo to avoid escaping + $ECHO "$_output" + echo + echo "TEST FAILED!" + echo + exit 1 elif ! echo "$_output" | grep -q "$_expected"; then - echo \$ "$_cmd" - $ECHO "$_output" - echo - echo "missing expected output '$_expected'" - echo - echo - echo "TEST FAILED!" - echo - exit 1 + echo \$ "$_cmd" + $ECHO "$_output" + echo + echo "missing expected output '$_expected'" + echo + echo + echo "TEST FAILED!" + echo + exit 1 else - if [ -n "${VERBOSE-}" -o -n "${VERBOSE_CMD-}" ]; then - echo \$ "$_cmd" - fi - if [ -n "${VERBOSE-}" -o -n "${VERBOSE_OUTPUT-}" ]; then - $ECHO "$_output" - fi + if [ -n "${VERBOSE-}" -o -n "${VERBOSE_CMD-}" ]; then + echo \$ "$_cmd" + fi + if [ -n "${VERBOSE-}" -o -n "${VERBOSE_OUTPUT-}" ]; then + $ECHO "$_output" + fi fi set -e } @@ -152,30 +152,30 @@ expect_output_fail() { _cmd="$@" _output=`$@ 2>&1` if [ $? -eq 0 ]; then - echo \$ "$_cmd" - # Using /bin/echo to avoid escaping - $ECHO "$_output" - echo - echo "TEST FAILED!" - echo - exit 1 + echo \$ "$_cmd" + # Using /bin/echo to avoid escaping + $ECHO "$_output" + echo + echo "TEST FAILED!" + echo + exit 1 elif ! echo "$_output" | grep -q "$_expected"; then - echo \$ "$_cmd" - $ECHO "$_output" - echo - echo "missing expected output '$_expected'" - echo - echo - echo "TEST FAILED!" - echo - exit 1 + echo \$ "$_cmd" + $ECHO "$_output" + echo + echo "missing expected output '$_expected'" + echo + echo + echo "TEST FAILED!" + echo + exit 1 else - if [ -n "${VERBOSE-}" -o -n "${VERBOSE_CMD-}" ]; then - echo \$ "$_cmd" - fi - if [ -n "${VERBOSE-}" -o -n "${VERBOSE_OUTPUT-}" ]; then - $ECHO "$_output" - fi + if [ -n "${VERBOSE-}" -o -n "${VERBOSE_CMD-}" ]; then + echo \$ "$_cmd" + fi + if [ -n "${VERBOSE-}" -o -n "${VERBOSE_OUTPUT-}" ]; then + $ECHO "$_output" + fi fi set -e } @@ -187,30 +187,30 @@ expect_not_output_ok() { _cmd="$@" _output=`$@ 2>&1` if [ $? -ne 0 ]; then - echo \$ "$_cmd" - # Using /bin/echo to avoid escaping - $ECHO "$_output" - echo - echo "TEST FAILED!" - echo - exit 1 + echo \$ "$_cmd" + # Using /bin/echo to avoid escaping + $ECHO "$_output" + echo + echo "TEST FAILED!" + echo + exit 1 elif echo "$_output" | grep -q "$_expected"; then - echo \$ "$_cmd" - $ECHO "$_output" - echo - echo "unexpected output '$_expected'" - echo - echo - echo "TEST FAILED!" - echo - exit 1 + echo \$ "$_cmd" + $ECHO "$_output" + echo + echo "unexpected output '$_expected'" + echo + echo + echo "TEST FAILED!" + echo + exit 1 else - if [ -n "${VERBOSE-}" -o -n "${VERBOSE_CMD-}" ]; then - echo \$ "$_cmd" - fi - if [ -n "${VERBOSE-}" -o -n "${VERBOSE_OUTPUT-}" ]; then - $ECHO "$_output" - fi + if [ -n "${VERBOSE-}" -o -n "${VERBOSE_CMD-}" ]; then + echo \$ "$_cmd" + fi + if [ -n "${VERBOSE-}" -o -n "${VERBOSE_OUTPUT-}" ]; then + $ECHO "$_output" + fi fi set -e } @@ -218,9 +218,9 @@ expect_not_output_ok() { runtest() { local _testname="$1" if [ -n "${TESTNAME-}" ]; then - if ! echo "$_testname" | grep -q "$TESTNAME"; then - return 0 - fi + if ! echo "$_testname" | grep -q "$TESTNAME"; then + return 0 + fi fi pre "$_testname" @@ -231,9 +231,9 @@ runtest() { basic_install() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" try "$WORK_DIR/package/install.sh" --prefix="$PREFIX_DIR" try test -e "$PREFIX_DIR/something-to-install" try test -e "$PREFIX_DIR/dir-to-install/foo" @@ -245,9 +245,9 @@ runtest basic_install basic_uninstall() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" try "$WORK_DIR/package/install.sh" --prefix="$PREFIX_DIR" try "$WORK_DIR/package/install.sh --uninstall" --prefix="$PREFIX_DIR" try test ! -e "$PREFIX_DIR/something-to-install" @@ -263,10 +263,10 @@ not_installed_files() { mkdir -p "$WORK_DIR/overlay" touch "$WORK_DIR/overlay/not-installed" try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --non-installed-overlay="$WORK_DIR/overlay" + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --non-installed-overlay="$WORK_DIR/overlay" try test -e "$WORK_DIR/package/not-installed" try "$WORK_DIR/package/install.sh" --prefix="$PREFIX_DIR" try test ! -e "$PREFIX_DIR/not-installed" @@ -275,10 +275,10 @@ runtest not_installed_files tarball_with_package_name() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rustc-nightly + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rustc-nightly try "$WORK_DIR/rustc-nightly/install.sh" --prefix="$PREFIX_DIR" try test -e "$OUT_DIR/rustc-nightly.tar.gz" try test -e "$OUT_DIR/rustc-nightly.tar.xz" @@ -287,9 +287,9 @@ runtest tarball_with_package_name install_overwrite_backup() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" try mkdir -p "$PREFIX_DIR/bin" touch "$PREFIX_DIR/bin/program" try "$WORK_DIR/package/install.sh" --prefix="$PREFIX_DIR" @@ -300,10 +300,10 @@ runtest install_overwrite_backup bulk_directory() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --bulk-dirs=dir-to-install + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --bulk-dirs=dir-to-install try "$WORK_DIR/package/install.sh" --prefix="$PREFIX_DIR" try test -e "$PREFIX_DIR/something-to-install" try test -e "$PREFIX_DIR/dir-to-install/foo" @@ -317,10 +317,10 @@ runtest bulk_directory bulk_directory_overwrite() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --bulk-dirs=dir-to-install + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --bulk-dirs=dir-to-install try mkdir -p "$PREFIX_DIR/dir-to-install" try touch "$PREFIX_DIR/dir-to-install/overwrite" try "$WORK_DIR/package/install.sh" --prefix="$PREFIX_DIR" @@ -333,10 +333,10 @@ runtest bulk_directory_overwrite bulk_directory_overwrite_existing_backup() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --bulk-dirs=dir-to-install + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --bulk-dirs=dir-to-install try mkdir -p "$PREFIX_DIR/dir-to-install" try touch "$PREFIX_DIR/dir-to-install/overwrite" # This time we've already got an existing backup of the overwritten directory. @@ -351,10 +351,10 @@ runtest bulk_directory_overwrite_existing_backup nested_bulk_directory() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image4" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --bulk-dirs=dir-to-install/qux + --image-dir="$TEST_DIR/image4" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --bulk-dirs=dir-to-install/qux try "$WORK_DIR/package/install.sh" --prefix="$PREFIX_DIR" try test -e "$PREFIX_DIR/dir-to-install/qux/bar" try "$WORK_DIR/package/install.sh" --prefix="$PREFIX_DIR" --uninstall @@ -364,10 +364,10 @@ runtest nested_bulk_directory only_bulk_directory_no_files() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image5" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --bulk-dirs=dir-to-install + --image-dir="$TEST_DIR/image5" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --bulk-dirs=dir-to-install try "$WORK_DIR/package/install.sh" --prefix="$PREFIX_DIR" try test -e "$PREFIX_DIR/dir-to-install/foo" try "$WORK_DIR/package/install.sh" --prefix="$PREFIX_DIR" --uninstall @@ -379,10 +379,10 @@ nested_not_installed_files() { mkdir -p "$WORK_DIR/overlay" touch "$WORK_DIR/overlay/not-installed" try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image4" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --non-installed-overlay="$WORK_DIR/overlay" + --image-dir="$TEST_DIR/image4" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --non-installed-overlay="$WORK_DIR/overlay" try test -e "$WORK_DIR/package/not-installed" try "$WORK_DIR/package/install.sh" --prefix="$PREFIX_DIR" try test ! -e "$PREFIX_DIR/not-installed" @@ -391,15 +391,15 @@ runtest nested_not_installed_files multiple_components() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR/c1" \ - --output-dir="$OUT_DIR/c1" \ - --component-name=rustc + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR/c1" \ + --output-dir="$OUT_DIR/c1" \ + --component-name=rustc try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image3" \ - --work-dir="$WORK_DIR/c2" \ - --output-dir="$OUT_DIR/c2" \ - --component-name=cargo + --image-dir="$TEST_DIR/image3" \ + --work-dir="$WORK_DIR/c2" \ + --output-dir="$OUT_DIR/c2" \ + --component-name=cargo try "$WORK_DIR/c1/package/install.sh" --prefix="$PREFIX_DIR" try "$WORK_DIR/c2/package/install.sh" --prefix="$PREFIX_DIR" try test -e "$PREFIX_DIR/something-to-install" @@ -422,15 +422,15 @@ runtest multiple_components uninstall_from_installed_script() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR/c1" \ - --output-dir="$OUT_DIR/c1" \ - --component-name=rustc + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR/c1" \ + --output-dir="$OUT_DIR/c1" \ + --component-name=rustc try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image3" \ - --work-dir="$WORK_DIR/c2" \ - --output-dir="$OUT_DIR/c2" \ - --component-name=cargo + --image-dir="$TEST_DIR/image3" \ + --work-dir="$WORK_DIR/c2" \ + --output-dir="$OUT_DIR/c2" \ + --component-name=cargo try "$WORK_DIR/c1/package/install.sh" --prefix="$PREFIX_DIR" try "$WORK_DIR/c2/package/install.sh" --prefix="$PREFIX_DIR" try test -e "$PREFIX_DIR/something-to-install" @@ -453,12 +453,13 @@ runtest uninstall_from_installed_script uninstall_from_installed_script_with_args_fails() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR/c1" \ - --output-dir="$OUT_DIR/c1" \ - --component-name=rustc + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR/c1" \ + --output-dir="$OUT_DIR/c1" \ + --component-name=rustc try "$WORK_DIR/c1/package/install.sh" --prefix="$PREFIX_DIR" - expect_output_fail "uninstall.sh does not take any arguments" sh "$PREFIX_DIR/lib/packagelib/uninstall.sh" --prefix=foo + expect_output_fail "uninstall.sh does not take any arguments" \ + sh "$PREFIX_DIR/lib/packagelib/uninstall.sh" --prefix=foo } runtest uninstall_from_installed_script_with_args_fails @@ -466,22 +467,22 @@ runtest uninstall_from_installed_script_with_args_fails combine_installers() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rustc \ - --component-name=rustc - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image3" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=cargo \ - --component-name=cargo + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rustc \ + --component-name=rustc + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image3" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=cargo \ + --component-name=cargo try sh "$S/combine-installers.sh" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust \ - --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz" + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust \ + --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz" try "$WORK_DIR/rust/install.sh" --prefix="$PREFIX_DIR" try test -e "$PREFIX_DIR/something-to-install" try test -e "$PREFIX_DIR/dir-to-install/foo" @@ -502,28 +503,28 @@ runtest combine_installers combine_three_installers() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rustc \ - --component-name=rustc - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image3" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=cargo \ - --component-name=cargo - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image4" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust-docs \ - --component-name=rust-docs + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rustc \ + --component-name=rustc + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image3" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=cargo \ + --component-name=cargo + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image4" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust-docs \ + --component-name=rust-docs try sh "$S/combine-installers.sh" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust \ - --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust \ + --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" try "$WORK_DIR/rust/install.sh" --prefix="$PREFIX_DIR" try test -e "$PREFIX_DIR/something-to-install" try test -e "$PREFIX_DIR/dir-to-install/foo" @@ -546,25 +547,25 @@ runtest combine_three_installers combine_installers_with_overlay() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rustc \ - --component-name=rustc - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image3" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=cargo \ - --component-name=cargo + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rustc \ + --component-name=rustc + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image3" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=cargo \ + --component-name=cargo mkdir -p "$WORK_DIR/overlay" touch "$WORK_DIR/overlay/README" try sh "$S/combine-installers.sh" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust \ - --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz" \ - --non-installed-overlay="$WORK_DIR/overlay" + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust \ + --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz" \ + --non-installed-overlay="$WORK_DIR/overlay" try test -e "$WORK_DIR/rust/README" try "$WORK_DIR/rust/install.sh" --prefix="$PREFIX_DIR" try test ! -e "$PREFIX_DIR/README" @@ -573,23 +574,23 @@ runtest combine_installers_with_overlay combined_with_bulk_dirs() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rustc \ - --component-name=rustc \ - --bulk-dirs=dir-to-install - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image3" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=cargo \ - --component-name=cargo + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rustc \ + --component-name=rustc \ + --bulk-dirs=dir-to-install + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image3" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=cargo \ + --component-name=cargo try sh "$S/combine-installers.sh" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust \ - --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz" + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust \ + --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz" try "$WORK_DIR/rust/install.sh" --prefix="$PREFIX_DIR" try test -e "$PREFIX_DIR/dir-to-install/foo" try "$WORK_DIR/rust/install.sh --uninstall" --prefix="$PREFIX_DIR" @@ -599,25 +600,25 @@ runtest combined_with_bulk_dirs combine_install_with_separate_uninstall() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rustc \ - --component-name=rustc \ - --rel-manifest-dir=rustlib - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image3" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=cargo \ - --component-name=cargo \ - --rel-manifest-dir=rustlib + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rustc \ + --component-name=rustc \ + --rel-manifest-dir=rustlib + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image3" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=cargo \ + --component-name=cargo \ + --rel-manifest-dir=rustlib try sh "$S/combine-installers.sh" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust \ - --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz" \ - --rel-manifest-dir=rustlib + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust \ + --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz" \ + --rel-manifest-dir=rustlib try "$WORK_DIR/rust/install.sh" --prefix="$PREFIX_DIR" try test -e "$PREFIX_DIR/something-to-install" try test -e "$PREFIX_DIR/dir-to-install/foo" @@ -639,28 +640,28 @@ runtest combine_install_with_separate_uninstall select_components_to_install() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rustc \ - --component-name=rustc - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image3" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=cargo \ - --component-name=cargo - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image4" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust-docs \ - --component-name=rust-docs + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rustc \ + --component-name=rustc + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image3" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=cargo \ + --component-name=cargo + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image4" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust-docs \ + --component-name=rust-docs try sh "$S/combine-installers.sh" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust \ - --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust \ + --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" try "$WORK_DIR/rust/install.sh" --prefix="$PREFIX_DIR" --components=rustc try test -e "$PREFIX_DIR/bin/program" try test ! -e "$PREFIX_DIR/bin/cargo" @@ -680,7 +681,8 @@ select_components_to_install() { try test -e "$PREFIX_DIR/bin/program" try test -e "$PREFIX_DIR/bin/cargo" try test ! -e "$PREFIX_DIR/baz" - try "$WORK_DIR/rust/install.sh --uninstall" --prefix="$PREFIX_DIR" --components=rustc,cargo,rust-docs + try "$WORK_DIR/rust/install.sh --uninstall" --prefix="$PREFIX_DIR" \ + --components=rustc,cargo,rust-docs try test ! -e "$PREFIX_DIR/bin/program" try test ! -e "$PREFIX_DIR/bin/cargo" try test ! -e "$PREFIX_DIR/baz" @@ -690,28 +692,28 @@ runtest select_components_to_install select_components_to_uninstall() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rustc \ - --component-name=rustc - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image3" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=cargo \ - --component-name=cargo - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image4" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust-docs \ - --component-name=rust-docs + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rustc \ + --component-name=rustc + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image3" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=cargo \ + --component-name=cargo + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image4" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust-docs \ + --component-name=rust-docs try sh "$S/combine-installers.sh" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust \ - --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust \ + --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" try "$WORK_DIR/rust/install.sh" --prefix="$PREFIX_DIR" try "$WORK_DIR/rust/install.sh --uninstall" --prefix="$PREFIX_DIR" --components=rustc try test ! -e "$PREFIX_DIR/bin/program" @@ -733,7 +735,8 @@ select_components_to_uninstall() { try test ! -e "$PREFIX_DIR/bin/cargo" try test -e "$PREFIX_DIR/baz" try "$WORK_DIR/rust/install.sh" --prefix="$PREFIX_DIR" - try "$WORK_DIR/rust/install.sh --uninstall" --prefix="$PREFIX_DIR" --components=rustc,cargo,rust-docs + try "$WORK_DIR/rust/install.sh --uninstall" --prefix="$PREFIX_DIR" \ + --components=rustc,cargo,rust-docs try test ! -e "$PREFIX_DIR/bin/program" try test ! -e "$PREFIX_DIR/bin/cargo" try test ! -e "$PREFIX_DIR/baz" @@ -743,56 +746,57 @@ runtest select_components_to_uninstall invalid_component() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rustc \ - --component-name=rustc - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image3" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=cargo \ - --component-name=cargo - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image4" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust-docs \ - --component-name=rust-docs + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rustc \ + --component-name=rustc + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image3" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=cargo \ + --component-name=cargo + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image4" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust-docs \ + --component-name=rust-docs try sh "$S/combine-installers.sh" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust \ - --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" - expect_output_fail "unknown component" "$WORK_DIR/rust/install.sh" --prefix="$PREFIX_DIR" --components=foo + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust \ + --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" + expect_output_fail "unknown component" "$WORK_DIR/rust/install.sh" --prefix="$PREFIX_DIR" \ + --components=foo } runtest invalid_component without_components() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rustc \ - --component-name=rustc - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image3" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=cargo \ - --component-name=cargo - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image4" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust-docs \ - --component-name=rust-docs + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rustc \ + --component-name=rustc + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image3" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=cargo \ + --component-name=cargo + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image4" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust-docs \ + --component-name=rust-docs try sh "$S/combine-installers.sh" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust \ - --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust \ + --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" try "$WORK_DIR/rust/install.sh" --prefix="$PREFIX_DIR" --without=rust-docs try test -e "$PREFIX_DIR/bin/program" try test -e "$PREFIX_DIR/bin/cargo" @@ -815,28 +819,28 @@ runtest without_components # --without causes components to remain installed uninstall_without_components() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rustc \ - --component-name=rustc - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image3" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=cargo \ - --component-name=cargo - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image4" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust-docs \ - --component-name=rust-docs + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rustc \ + --component-name=rustc + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image3" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=cargo \ + --component-name=cargo + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image4" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust-docs \ + --component-name=rust-docs try sh "$S/combine-installers.sh" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust \ - --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust \ + --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" try "$WORK_DIR/rust/install.sh" --prefix="$PREFIX_DIR" try "$WORK_DIR/rust/install.sh --uninstall" --prefix="$PREFIX_DIR" --without=rust-docs try test ! -e "$PREFIX_DIR/bin/program" @@ -857,88 +861,88 @@ runtest uninstall_without_components without_any_components() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rustc \ - --component-name=rustc - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image3" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=cargo \ - --component-name=cargo - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image4" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust-docs \ - --component-name=rust-docs + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rustc \ + --component-name=rustc + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image3" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=cargo \ + --component-name=cargo + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image4" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust-docs \ + --component-name=rust-docs try sh "$S/combine-installers.sh" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust \ - --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust \ + --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" expect_output_fail "no components selected for installation" \ - "$WORK_DIR/rust/install.sh" --prefix="$PREFIX_DIR" --without=rust-docs,rustc,cargo + "$WORK_DIR/rust/install.sh" --prefix="$PREFIX_DIR" --without=rust-docs,rustc,cargo } runtest without_any_components uninstall_without_any_components() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rustc \ - --component-name=rustc - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image3" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=cargo \ - --component-name=cargo - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image4" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust-docs \ - --component-name=rust-docs + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rustc \ + --component-name=rustc + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image3" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=cargo \ + --component-name=cargo + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image4" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust-docs \ + --component-name=rust-docs try sh "$S/combine-installers.sh" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust \ - --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust \ + --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" try "$WORK_DIR/rust/install.sh" --prefix="$PREFIX_DIR" expect_output_fail "no components selected for uninstallation" \ - "$WORK_DIR/rust/install.sh" --prefix="$PREFIX_DIR" \ - --uninstall --without=rust-docs,rustc,cargo + "$WORK_DIR/rust/install.sh" --prefix="$PREFIX_DIR" \ + --uninstall --without=rust-docs,rustc,cargo } runtest uninstall_without_any_components list_components() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rustc \ - --component-name=rustc - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image3" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=cargo \ - --component-name=cargo - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image4" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust-docs \ - --component-name=rust-docs + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rustc \ + --component-name=rustc + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image3" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=cargo \ + --component-name=cargo + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image4" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust-docs \ + --component-name=rust-docs try sh "$S/combine-installers.sh" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust \ - --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust \ + --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" expect_output_ok "rustc" "$WORK_DIR/rust/install.sh" --list-components expect_output_ok "cargo" "$WORK_DIR/rust/install.sh" --list-components expect_output_ok "rust-docs" "$WORK_DIR/rust/install.sh" --list-components @@ -947,32 +951,32 @@ runtest list_components combined_remains() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rustc \ - --component-name=rustc - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image3" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=cargo \ - --component-name=cargo - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image4" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust-docs \ - --component-name=rust-docs + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rustc \ + --component-name=rustc + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image3" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=cargo \ + --component-name=cargo + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image4" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust-docs \ + --component-name=rust-docs try sh "$S/combine-installers.sh" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust \ - --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust \ + --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" for component in rustc cargo rust-docs; do - # rustbuild wants the original extracted package intact too - try test -d "$WORK_DIR/$component/$component" - try test -d "$WORK_DIR/rust/$component" + # rustbuild wants the original extracted package intact too + try test -d "$WORK_DIR/$component/$component" + try test -d "$WORK_DIR/rust/$component" done } runtest combined_remains @@ -982,34 +986,34 @@ runtest combined_remains cannot_write_error() { # chmod doesn't work on windows if [ ! -n "${WINDOWS-}" ]; then - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" - chmod u-w "$PREFIX_DIR" - expect_fail "$WORK_DIR/package/install.sh" --prefix="$PREFIX_DIR" - chmod u+w "$PREFIX_DIR" + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" + chmod u-w "$PREFIX_DIR" + expect_fail "$WORK_DIR/package/install.sh" --prefix="$PREFIX_DIR" + chmod u+w "$PREFIX_DIR" fi } runtest cannot_write_error cannot_install_to_installer() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=my-package + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=my-package expect_output_fail "cannot install to same directory as installer" \ - "$WORK_DIR/my-package/install.sh" --prefix="$WORK_DIR/my-package" + "$WORK_DIR/my-package/install.sh" --prefix="$WORK_DIR/my-package" } runtest cannot_install_to_installer upgrade_from_future_installer_error() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --rel-manifest-dir=rustlib + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --rel-manifest-dir=rustlib try "$WORK_DIR/package/install.sh" --prefix="$PREFIX_DIR" echo 100 > "$PREFIX_DIR/lib/rustlib/rust-installer-version" expect_fail "$WORK_DIR/package/install.sh" --prefix="$PREFIX_DIR" @@ -1018,9 +1022,9 @@ runtest upgrade_from_future_installer_error destdir() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" try "$WORK_DIR/package/install.sh" --destdir="$PREFIX_DIR/" --prefix=prefix try test -e "$PREFIX_DIR/prefix/bin/program" } @@ -1028,9 +1032,9 @@ runtest destdir destdir_no_trailing_slash() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" try "$WORK_DIR/package/install.sh" --destdir="$PREFIX_DIR" --prefix=prefix try test -e "$PREFIX_DIR/prefix/bin/program" } @@ -1055,7 +1059,7 @@ create_log() { try test -e "$PREFIX_DIR/lib/packagelib/install.log" local _log="$(cat "$PREFIX_DIR/lib/packagelib/install.log")" if [ -z "$_log" ]; then - fail "log is empty" + fail "log is empty" fi } runtest create_log @@ -1063,24 +1067,24 @@ runtest create_log leave_log_after_failure() { # chmod doesn't work on windows if [ ! -n "${WINDOWS-}" ]; then - try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" - mkdir -p "$PREFIX_DIR/lib/packagelib" - touch "$PREFIX_DIR/lib/packagelib/components" - chmod u-w "$PREFIX_DIR/lib/packagelib/components" - expect_fail "$WORK_DIR/package/install.sh" --prefix="$PREFIX_DIR" - chmod u+w "$PREFIX_DIR/lib/packagelib/components" - try test -e "$PREFIX_DIR/lib/packagelib/install.log" - local _log="$(cat "$PREFIX_DIR/lib/packagelib/install.log")" - if [ -z "$_log" ]; then - fail "log is empty" - fi - # script should tell user where the logs are - if ! grep -q "see logs at" "$PREFIX_DIR/lib/packagelib/install.log"; then - fail "missing log message" - fi + try sh "$S/gen-installer.sh" \ + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" + mkdir -p "$PREFIX_DIR/lib/packagelib" + touch "$PREFIX_DIR/lib/packagelib/components" + chmod u-w "$PREFIX_DIR/lib/packagelib/components" + expect_fail "$WORK_DIR/package/install.sh" --prefix="$PREFIX_DIR" + chmod u+w "$PREFIX_DIR/lib/packagelib/components" + try test -e "$PREFIX_DIR/lib/packagelib/install.log" + local _log="$(cat "$PREFIX_DIR/lib/packagelib/install.log")" + if [ -z "$_log" ]; then + fail "log is empty" + fi + # script should tell user where the logs are + if ! grep -q "see logs at" "$PREFIX_DIR/lib/packagelib/install.log"; then + fail "missing log message" + fi fi } runtest leave_log_after_failure @@ -1088,9 +1092,9 @@ runtest leave_log_after_failure # https://github.com/rust-lang/rust-installer/issues/22 help() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" try "$WORK_DIR/package/install.sh" --help } runtest help @@ -1098,9 +1102,9 @@ runtest help # https://github.com/rust-lang/rust-installer/issues/31 CDPATH_does_not_destroy_things() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" + --image-dir="$TEST_DIR/image1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" cd "$WORK_DIR" || exit 1 export CDPATH="../$(basename $WORK_DIR)/foo" try sh "package/install.sh" --prefix="$PREFIX_DIR" @@ -1115,9 +1119,9 @@ runtest CDPATH_does_not_destroy_things docdir_default() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image-docdir1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" + --image-dir="$TEST_DIR/image-docdir1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" try "$WORK_DIR/package/install.sh" --prefix="$PREFIX_DIR" try test -e "$PREFIX_DIR/share/doc/rust/README" try test -e "$PREFIX_DIR/share/doc/rust/rustdocs.txt" @@ -1126,9 +1130,9 @@ runtest docdir_default docdir() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image-docdir1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" + --image-dir="$TEST_DIR/image-docdir1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" try mkdir "$WORK_DIR/docdir" try "$WORK_DIR/package/install.sh" --prefix="$PREFIX_DIR" --docdir="$WORK_DIR/docdir" try test -e "$WORK_DIR/docdir/README" @@ -1138,22 +1142,22 @@ runtest docdir docdir_combined() { try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image-docdir1" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ + --image-dir="$TEST_DIR/image-docdir1" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ --package-name="rustc" \ --component-name="rustc" try sh "$S/gen-installer.sh" \ - --image-dir="$TEST_DIR/image-docdir2" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ + --image-dir="$TEST_DIR/image-docdir2" \ + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ --package-name="cargo" \ --component-name="cargo" try sh "$S/combine-installers.sh" \ - --work-dir="$WORK_DIR" \ - --output-dir="$OUT_DIR" \ - --package-name=rust \ - --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz" + --work-dir="$WORK_DIR" \ + --output-dir="$OUT_DIR" \ + --package-name=rust \ + --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz" try mkdir "$WORK_DIR/docdir" try "$WORK_DIR/rust/install.sh" --prefix="$PREFIX_DIR" --docdir="$WORK_DIR/docdir" try test -e "$WORK_DIR/docdir/README" diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs index 197e9a9965f..64ba79dc185 100644 --- a/src/tools/tidy/src/bins.rs +++ b/src/tools/tidy/src/bins.rs @@ -95,17 +95,41 @@ mod os_impl { return true; } + // FIXME: check when rust-installer test sh files will be removed, + // and then remove them from exclude list + const RI_EXCLUSION_LIST: &[&str] = &[ + "src/tools/rust-installer/test/image1/bin/program", + "src/tools/rust-installer/test/image1/bin/program2", + "src/tools/rust-installer/test/image1/bin/bad-bin", + "src/tools/rust-installer/test/image2/bin/oldprogram", + "src/tools/rust-installer/test/image3/bin/cargo", + ]; + + fn filter_rust_installer_no_so_bins(path: &Path) -> bool { + RI_EXCLUSION_LIST.iter().any(|p| path.ends_with(p)) + } + #[cfg(unix)] pub fn check(path: &Path, bad: &mut bool) { use std::ffi::OsStr; const ALLOWED: &[&str] = &["configure", "x"]; + for p in RI_EXCLUSION_LIST { + if !path.join(Path::new(p)).exists() { + tidy_error!(bad, "rust-installer test bins missed: {p}"); + } + } + // FIXME: we don't need to look at all binaries, only files that have been modified in this branch // (e.g. using `git ls-files`). walk_no_read( &[path], - |path, _is_dir| filter_dirs(path) || path.ends_with("src/etc"), + |path, _is_dir| { + filter_dirs(path) + || path.ends_with("src/etc") + || filter_rust_installer_no_so_bins(path) + }, &mut |entry| { let file = entry.path(); let extension = file.extension(); diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index b6c57342a05..ecc84c1618c 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -99,6 +99,8 @@ const EXCEPTIONS_BOOTSTRAP: &[(&str, &str)] = &[ /// these and all their dependencies *must not* be in the exception list. const RUNTIME_CRATES: &[&str] = &["std", "core", "alloc", "test", "panic_abort", "panic_unwind"]; +const PERMITTED_DEPS_LOCATION: &str = concat!(file!(), ":", line!()); + /// Crates rustc is allowed to depend on. Avoid adding to the list if possible. /// /// This list is here to provide a speed-bump to adding a new dependency to @@ -120,10 +122,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "byteorder", // via ruzstd in object in thorin-dwp "cc", "cfg-if", - "chalk-derive", - "chalk-engine", - "chalk-ir", - "chalk-solve", "compiler_builtins", "convert_case", // dependency of derive_more "cpufeatures", @@ -133,6 +131,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "crossbeam-epoch", "crossbeam-utils", "crypto-common", + "cstr", "datafrog", "derive_more", "digest", @@ -147,7 +146,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "fallible-iterator", // dependency of `thorin` "fastrand", "field-offset", - "fixedbitset", "flate2", "fluent-bundle", "fluent-langneg", @@ -197,7 +195,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "parking_lot_core", "pathdiff", "perf-event-open-sys", - "petgraph", "pin-project-lite", "polonius-engine", "ppv-lite86", @@ -500,6 +497,7 @@ fn check_permitted_dependencies( restricted_dependency_crates: &[&'static str], bad: &mut bool, ) { + let mut has_permitted_dep_error = false; let mut deps = HashSet::new(); for to_check in restricted_dependency_crates { let to_check = pkg_from_name(metadata, to_check); @@ -534,6 +532,7 @@ fn check_permitted_dependencies( "could not find allowed package `{permitted}`\n\ Remove from PERMITTED_DEPENDENCIES list if it is no longer used.", ); + has_permitted_dep_error = true; } } @@ -546,9 +545,14 @@ fn check_permitted_dependencies( if dep.source.is_some() { if !permitted_dependencies.contains(dep.name.as_str()) { tidy_error!(bad, "Dependency for {descr} not explicitly permitted: {}", dep.id); + has_permitted_dep_error = true; } } } + + if has_permitted_dep_error { + eprintln!("Go to `{PERMITTED_DEPS_LOCATION}` for the list."); + } } /// Finds a package with the given name. diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 3ed587caadc..55bf38110a6 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -11,7 +11,7 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. const ISSUES_ENTRY_LIMIT: usize = 1896; -const ROOT_ENTRY_LIMIT: usize = 871; +const ROOT_ENTRY_LIMIT: usize = 870; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs index 3539943ebef..185e1f3209b 100644 --- a/src/tools/tidy/src/walk.rs +++ b/src/tools/tidy/src/walk.rs @@ -4,6 +4,8 @@ use std::{ffi::OsStr, fs::File, io::Read, path::Path}; /// The default directory filter. pub fn filter_dirs(path: &Path) -> bool { + // FIXME: sync submodule exclusion list with rustfmt.toml + // bootstrap/etc let skip = [ "tidy-test-file", "compiler/rustc_codegen_cranelift", @@ -15,9 +17,7 @@ pub fn filter_dirs(path: &Path) -> bool { "src/tools/cargo", "src/tools/clippy", "src/tools/miri", - "src/tools/rls", "src/tools/rust-analyzer", - "src/tools/rust-installer", "src/tools/rustfmt", "src/doc/book", "src/doc/edition-guide", diff --git a/tests/mir-opt/issue_99325.main.built.after.mir b/tests/mir-opt/issue_99325.main.built.after.mir index d8a88a0635c..0fe66d3fb70 100644 --- a/tests/mir-opt/issue_99325.main.built.after.mir +++ b/tests/mir-opt/issue_99325.main.built.after.mir @@ -2,7 +2,7 @@ | User Type Annotations | 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)]) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:10:16: 10:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} -| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Unevaluated([], DefId(0:8 ~ issue_99325[22bb]::main::{constant#1})) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:11:16: 11:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: UnevaluatedConst { def: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), substs: [] } }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:11:16: 11:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} | fn main() -> () { let mut _0: (); diff --git a/tests/rustdoc-gui/label-next-to-symbol.goml b/tests/rustdoc-gui/label-next-to-symbol.goml index 6c6380256bd..eb603d6c6b6 100644 --- a/tests/rustdoc-gui/label-next-to-symbol.goml +++ b/tests/rustdoc-gui/label-next-to-symbol.goml @@ -37,7 +37,6 @@ compare-elements-position: ( ("y"), ) - // Mobile view set-window-size: (600, 600) // staggered layout with 2em spacing @@ -64,3 +63,14 @@ compare-elements-position-false: ( "//*[@class='desc docblock-short'][text()='a thing with a label']", ("y"), ) + +// Ensure it doesn't expand. +set-window-size: (800, 800) +go-to: "file://" + |DOC_PATH| + "/test_docs/cfgs/index.html" +// This part of the tags should not be on the same line as the beginning since the width +// is too small for that. +compare-elements-position-false: ( + "//*[@class='stab portability']/code[text()='appservice-api-c']", + "//*[@class='stab portability']/code[text()='server']", + ("y"), +) diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs index c040fa02dff..ecf3a7cc147 100644 --- a/tests/rustdoc-gui/src/test_docs/lib.rs +++ b/tests/rustdoc-gui/src/test_docs/lib.rs @@ -507,3 +507,12 @@ pub mod fields { }, } } + +pub mod cfgs { + #[doc(cfg(all( + any(not(feature = "appservice-api-c"), not(feature = "appservice-api-s")), + any(not(feature = "client"), not(feature = "server")), + )))] + /// Some docs. + pub mod cfgs {} +} diff --git a/tests/ui-fulldeps/missing-rustc-driver-error.stderr b/tests/ui-fulldeps/missing-rustc-driver-error.stderr index ad03ba0103c..939e888e5cb 100644 --- a/tests/ui-fulldeps/missing-rustc-driver-error.stderr +++ b/tests/ui-fulldeps/missing-rustc-driver-error.stderr @@ -10,15 +10,7 @@ error: crate `indexmap` required to be available in rlib format, but was not fou error: crate `hashbrown` required to be available in rlib format, but was not found in this form -error: crate `ahash` required to be available in rlib format, but was not found in this form +error: crate `equivalent` required to be available in rlib format, but was not found in this form -error: crate `once_cell` required to be available in rlib format, but was not found in this form - -error: crate `getrandom` required to be available in rlib format, but was not found in this form - -error: crate `cfg_if` required to be available in rlib format, but was not found in this form - -error: crate `libc` required to be available in rlib format, but was not found in this form - -error: aborting due to 10 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/abi/foreign/foreign-fn-with-byval.rs b/tests/ui/abi/foreign/foreign-fn-with-byval.rs index f366b6ee1bd..e20ee0da45d 100644 --- a/tests/ui/abi/foreign/foreign-fn-with-byval.rs +++ b/tests/ui/abi/foreign/foreign-fn-with-byval.rs @@ -1,5 +1,5 @@ // run-pass -#![allow(improper_ctypes)] +#![allow(improper_ctypes, improper_ctypes_definitions)] // ignore-wasm32-bare no libc to test ffi with diff --git a/tests/ui/abi/issue-94223.rs b/tests/ui/abi/issue-94223.rs new file mode 100644 index 00000000000..79d6b94031b --- /dev/null +++ b/tests/ui/abi/issue-94223.rs @@ -0,0 +1,8 @@ +// check-pass +#![allow(improper_ctypes_definitions)] +#![crate_type = "lib"] + +// Check that computing the fn abi for `bad`, with a external ABI fn ptr that is not FFI-safe, does +// not ICE. + +pub fn bad(f: extern "C" fn([u8])) {} diff --git a/tests/ui/associated-inherent-types/assoc-inherent-unstable.rs b/tests/ui/associated-inherent-types/assoc-inherent-unstable.rs index 34b4e47bf46..152bb7a60a7 100644 --- a/tests/ui/associated-inherent-types/assoc-inherent-unstable.rs +++ b/tests/ui/associated-inherent-types/assoc-inherent-unstable.rs @@ -1,6 +1,9 @@ // aux-crate:aux=assoc-inherent-unstable.rs // edition: 2021 +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + type Data = aux::Owner::Data; //~ ERROR use of unstable library feature 'data' fn main() {} diff --git a/tests/ui/associated-inherent-types/assoc-inherent-unstable.stderr b/tests/ui/associated-inherent-types/assoc-inherent-unstable.stderr index c0be8bfd79b..415ee0193c9 100644 --- a/tests/ui/associated-inherent-types/assoc-inherent-unstable.stderr +++ b/tests/ui/associated-inherent-types/assoc-inherent-unstable.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature 'data' - --> $DIR/assoc-inherent-unstable.rs:4:13 + --> $DIR/assoc-inherent-unstable.rs:7:13 | LL | type Data = aux::Owner::Data; | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.rs b/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.rs index f41574403d8..33c73c3db89 100644 --- a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.rs +++ b/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.rs @@ -1,5 +1,7 @@ // known-bug: #108491 +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] // FIXME(inherent_associated_types): This should pass. struct Foo { @@ -8,3 +10,5 @@ struct Foo { impl Foo { pub type Bar = usize; } + +fn main() {} diff --git a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.stderr b/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.stderr index f313c494671..23269e1afab 100644 --- a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.stderr +++ b/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.stderr @@ -1,49 +1,43 @@ -error[E0601]: `main` function not found in crate `cycle_iat_inside_of_adt` - --> $DIR/cycle-iat-inside-of-adt.rs:10:2 - | -LL | } - | ^ consider adding a `main` function to `$DIR/cycle-iat-inside-of-adt.rs` - error[E0391]: cycle detected when computing predicates of `Foo` - --> $DIR/cycle-iat-inside-of-adt.rs:5:1 + --> $DIR/cycle-iat-inside-of-adt.rs:7:1 | LL | struct Foo { | ^^^^^^^^^^ | note: ...which requires computing predicates of `Foo`... - --> $DIR/cycle-iat-inside-of-adt.rs:5:1 + --> $DIR/cycle-iat-inside-of-adt.rs:7:1 | LL | struct Foo { | ^^^^^^^^^^ note: ...which requires computing inferred outlives predicates of `Foo`... - --> $DIR/cycle-iat-inside-of-adt.rs:5:1 + --> $DIR/cycle-iat-inside-of-adt.rs:7:1 | LL | struct Foo { | ^^^^^^^^^^ = note: ...which requires computing the inferred outlives predicates for items in this crate... note: ...which requires computing type of `Foo::bar`... - --> $DIR/cycle-iat-inside-of-adt.rs:6:5 + --> $DIR/cycle-iat-inside-of-adt.rs:8:5 | LL | bar: Self::Bar, | ^^^^^^^^^^^^^^ note: ...which requires computing normalized predicates of `Foo`... - --> $DIR/cycle-iat-inside-of-adt.rs:5:1 + --> $DIR/cycle-iat-inside-of-adt.rs:7:1 | LL | struct Foo { | ^^^^^^^^^^ = note: ...which again requires computing predicates of `Foo`, completing the cycle note: cycle used when collecting item types in top-level module - --> $DIR/cycle-iat-inside-of-adt.rs:5:1 - | -LL | / struct Foo { -LL | | bar: Self::Bar, -LL | | } -LL | | impl Foo { -LL | | pub type Bar = usize; -LL | | } - | |_^ + --> $DIR/cycle-iat-inside-of-adt.rs:3:1 + | +LL | / #![feature(inherent_associated_types)] +LL | | #![allow(incomplete_features)] +LL | | // FIXME(inherent_associated_types): This should pass. +LL | | +... | +LL | | +LL | | fn main() {} + | |____________^ -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0391, E0601. -For more information about an error, try `rustc --explain E0391`. +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/associated-inherent-types/dont-select-if-disabled.rs b/tests/ui/associated-inherent-types/dont-select-if-disabled.rs new file mode 100644 index 00000000000..472be4fbfbc --- /dev/null +++ b/tests/ui/associated-inherent-types/dont-select-if-disabled.rs @@ -0,0 +1,17 @@ +// Regression test for #113265. + +// Don't perform selection if the feature is not enabled to prevent cycle errors +// that exist due to current limitations of the implementation from masking the +// feature-gate error. See the aforementioned issue. +// This does lead to rustc not mentioning inherent associated types at usage-sites of +// IATs that were defined in an external crate but that's acceptable for now. + +// FIXME(inherent_associated_types): Revisit this decision once the implementation is smarter. + +// The following program would currently lead to a cycle if IATs were enabled. + +struct S(S::P); //~ ERROR ambiguous associated type + +impl S { type P = (); } //~ ERROR inherent associated types are unstable + +fn main() {} diff --git a/tests/ui/associated-inherent-types/dont-select-if-disabled.stderr b/tests/ui/associated-inherent-types/dont-select-if-disabled.stderr new file mode 100644 index 00000000000..87a3f35c968 --- /dev/null +++ b/tests/ui/associated-inherent-types/dont-select-if-disabled.stderr @@ -0,0 +1,24 @@ +error[E0223]: ambiguous associated type + --> $DIR/dont-select-if-disabled.rs:13:10 + | +LL | struct S(S::P); + | ^^^^ + | +help: if there were a trait named `Example` with associated type `P` implemented for `S`, you could use the fully-qualified path + | +LL | struct S(<S as Example>::P); + | ~~~~~~~~~~~~~~~~~ + +error[E0658]: inherent associated types are unstable + --> $DIR/dont-select-if-disabled.rs:15:10 + | +LL | impl S { type P = (); } + | ^^^^^^^^^^^^ + | + = note: see issue #8995 <https://github.com/rust-lang/rust/issues/8995> for more information + = help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0223, E0658. +For more information about an error, try `rustc --explain E0223`. diff --git a/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr b/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr index 8b6a8206569..6f206f2b89c 100644 --- a/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr +++ b/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr @@ -29,7 +29,13 @@ LL | type Item = &[T]; = note: see issue #8995 <https://github.com/rust-lang/rust/issues/8995> for more information = help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable -error: aborting due to 3 previous errors +error[E0223]: ambiguous associated type + --> $DIR/issue-109071.rs:15:22 + | +LL | fn T() -> Option<Self::Item> {} + | ^^^^^^^^^^ help: use the fully-qualified path: `<Windows<T> as IntoIterator>::Item` + +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0107, E0637, E0658. +Some errors have detailed explanations: E0107, E0223, E0637, E0658. For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/associated-inherent-types/issue-109071.rs b/tests/ui/associated-inherent-types/issue-109071.rs index 73b969d5940..951c708e3f9 100644 --- a/tests/ui/associated-inherent-types/issue-109071.rs +++ b/tests/ui/associated-inherent-types/issue-109071.rs @@ -13,6 +13,7 @@ impl<T> Windows { //~ ERROR: missing generics for struct `Windows` impl<T> Windows<T> { fn T() -> Option<Self::Item> {} + //[no_gate]~^ ERROR: ambiguous associated type } fn main() {} diff --git a/tests/ui/associated-inherent-types/issue-109789.stderr b/tests/ui/associated-inherent-types/issue-109789.stderr index 7af338274a1..84fc85cd09e 100644 --- a/tests/ui/associated-inherent-types/issue-109789.stderr +++ b/tests/ui/associated-inherent-types/issue-109789.stderr @@ -1,8 +1,8 @@ error[E0308]: mismatched types - --> $DIR/issue-109789.rs:18:1 + --> $DIR/issue-109789.rs:18:11 | LL | fn bar(_: Foo<for<'a> fn(&'a ())>::Assoc) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | = note: expected struct `Foo<fn(&'static ())>` found struct `Foo<for<'a> fn(&'a ())>` diff --git a/tests/ui/async-await/in-trait/return-not-existing-pair.current.stderr b/tests/ui/async-await/in-trait/return-not-existing-pair.current.stderr new file mode 100644 index 00000000000..56973a1d11a --- /dev/null +++ b/tests/ui/async-await/in-trait/return-not-existing-pair.current.stderr @@ -0,0 +1,39 @@ +error[E0726]: implicit elided lifetime not allowed here + --> $DIR/return-not-existing-pair.rs:12:20 + | +LL | impl<'a, 'b, T, U> MyTrait<T> for U { + | ^^^^^^^^^^ expected lifetime parameters + | +help: indicate the anonymous lifetimes + | +LL | impl<'a, 'b, T, U> MyTrait<'_, '_, T> for U { + | +++++++ + +error[E0412]: cannot find type `ConnImpl` in this scope + --> $DIR/return-not-existing-pair.rs:8:48 + | +LL | async fn foo(&'a self, key: &'b T) -> (&'a ConnImpl, &'b T); + | ^^^^^^^^ not found in this scope + +error[E0186]: method `foo` has a `&self` declaration in the trait, but not in the impl + --> $DIR/return-not-existing-pair.rs:14:5 + | +LL | async fn foo(&'a self, key: &'b T) -> (&'a ConnImpl, &'b T); + | ------------------------------------------------------------ `&self` used in trait +... +LL | async fn foo(_: T) -> (&'a U, &'b T) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&self` in impl + +error[E0308]: mismatched types + --> $DIR/return-not-existing-pair.rs:14:42 + | +LL | async fn foo(_: T) -> (&'a U, &'b T) {} + | ^^ expected `(&U, &T)`, found `()` + | + = note: expected tuple `(&'a U, &'b T)` + found unit type `()` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0186, E0308, E0412, E0726. +For more information about an error, try `rustc --explain E0186`. diff --git a/tests/ui/async-await/in-trait/return-not-existing-pair.next.stderr b/tests/ui/async-await/in-trait/return-not-existing-pair.next.stderr new file mode 100644 index 00000000000..56973a1d11a --- /dev/null +++ b/tests/ui/async-await/in-trait/return-not-existing-pair.next.stderr @@ -0,0 +1,39 @@ +error[E0726]: implicit elided lifetime not allowed here + --> $DIR/return-not-existing-pair.rs:12:20 + | +LL | impl<'a, 'b, T, U> MyTrait<T> for U { + | ^^^^^^^^^^ expected lifetime parameters + | +help: indicate the anonymous lifetimes + | +LL | impl<'a, 'b, T, U> MyTrait<'_, '_, T> for U { + | +++++++ + +error[E0412]: cannot find type `ConnImpl` in this scope + --> $DIR/return-not-existing-pair.rs:8:48 + | +LL | async fn foo(&'a self, key: &'b T) -> (&'a ConnImpl, &'b T); + | ^^^^^^^^ not found in this scope + +error[E0186]: method `foo` has a `&self` declaration in the trait, but not in the impl + --> $DIR/return-not-existing-pair.rs:14:5 + | +LL | async fn foo(&'a self, key: &'b T) -> (&'a ConnImpl, &'b T); + | ------------------------------------------------------------ `&self` used in trait +... +LL | async fn foo(_: T) -> (&'a U, &'b T) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&self` in impl + +error[E0308]: mismatched types + --> $DIR/return-not-existing-pair.rs:14:42 + | +LL | async fn foo(_: T) -> (&'a U, &'b T) {} + | ^^ expected `(&U, &T)`, found `()` + | + = note: expected tuple `(&'a U, &'b T)` + found unit type `()` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0186, E0308, E0412, E0726. +For more information about an error, try `rustc --explain E0186`. diff --git a/tests/ui/async-await/in-trait/return-not-existing-pair.rs b/tests/ui/async-await/in-trait/return-not-existing-pair.rs new file mode 100644 index 00000000000..d1b3832d12b --- /dev/null +++ b/tests/ui/async-await/in-trait/return-not-existing-pair.rs @@ -0,0 +1,19 @@ +// edition:2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + +#![feature(async_fn_in_trait)] + +trait MyTrait<'a, 'b, T> { + async fn foo(&'a self, key: &'b T) -> (&'a ConnImpl, &'b T); + //~^ ERROR: cannot find type `ConnImpl` in this scope [E0412] +} + +impl<'a, 'b, T, U> MyTrait<T> for U { + //~^ ERROR: implicit elided lifetime not allowed here [E0726] + async fn foo(_: T) -> (&'a U, &'b T) {} + //~^ ERROR: method `foo` has a `&self` declaration in the trait, but not in the impl [E0186] + //~| ERROR: mismatched types [E0308] +} + +fn main() {} diff --git a/tests/ui/async-await/in-trait/return-not-existing-type-wrapping-rpitit.current.stderr b/tests/ui/async-await/in-trait/return-not-existing-type-wrapping-rpitit.current.stderr new file mode 100644 index 00000000000..2564d68d591 --- /dev/null +++ b/tests/ui/async-await/in-trait/return-not-existing-type-wrapping-rpitit.current.stderr @@ -0,0 +1,9 @@ +error[E0412]: cannot find type `Missing` in this scope + --> $DIR/return-not-existing-type-wrapping-rpitit.rs:10:25 + | +LL | fn bar() -> Wrapper<Missing<impl Sized>>; + | ^^^^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/async-await/in-trait/return-not-existing-type-wrapping-rpitit.next.stderr b/tests/ui/async-await/in-trait/return-not-existing-type-wrapping-rpitit.next.stderr new file mode 100644 index 00000000000..2564d68d591 --- /dev/null +++ b/tests/ui/async-await/in-trait/return-not-existing-type-wrapping-rpitit.next.stderr @@ -0,0 +1,9 @@ +error[E0412]: cannot find type `Missing` in this scope + --> $DIR/return-not-existing-type-wrapping-rpitit.rs:10:25 + | +LL | fn bar() -> Wrapper<Missing<impl Sized>>; + | ^^^^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/async-await/in-trait/return-not-existing-type-wrapping-rpitit.rs b/tests/ui/async-await/in-trait/return-not-existing-type-wrapping-rpitit.rs new file mode 100644 index 00000000000..37c02827e8d --- /dev/null +++ b/tests/ui/async-await/in-trait/return-not-existing-type-wrapping-rpitit.rs @@ -0,0 +1,20 @@ +// edition:2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + +#![feature(return_position_impl_trait_in_trait)] + +struct Wrapper<T>(T); + +trait Foo { + fn bar() -> Wrapper<Missing<impl Sized>>; + //~^ ERROR: cannot find type `Missing` in this scope [E0412] +} + +impl Foo for () { + fn bar() -> Wrapper<i32> { + Wrapper(0) + } +} + +fn main() {} diff --git a/tests/ui/chalkify/arithmetic.rs b/tests/ui/chalkify/arithmetic.rs deleted file mode 100644 index 6c78a71b0fc..00000000000 --- a/tests/ui/chalkify/arithmetic.rs +++ /dev/null @@ -1,20 +0,0 @@ -// check-pass -// compile-flags: -Z trait-solver=chalk - -fn main() { - 1 + 2; - 3 * 6; - 2 - 5; - 17 / 6; - 23 % 11; - 4 & 6; - 7 | 15; - 4 << 7; - 123 >> 3; - 1 == 2; - 5 != 5; - 6 < 2; - 7 > 11; - 3 <= 1; - 9 >= 14; -} diff --git a/tests/ui/chalkify/assert.rs b/tests/ui/chalkify/assert.rs deleted file mode 100644 index 834c8935e76..00000000000 --- a/tests/ui/chalkify/assert.rs +++ /dev/null @@ -1,6 +0,0 @@ -// run-pass -// compile-flags: -Z trait-solver=chalk - -fn main() { - assert_eq!(1, 1); -} diff --git a/tests/ui/chalkify/basic.rs b/tests/ui/chalkify/basic.rs deleted file mode 100644 index 4a7cd939669..00000000000 --- a/tests/ui/chalkify/basic.rs +++ /dev/null @@ -1,12 +0,0 @@ -// check-pass -// compile-flags: -Z trait-solver=chalk - -trait Foo {} - -struct Bar {} - -impl Foo for Bar {} - -fn main() -> () { - let _ = Bar {}; -} diff --git a/tests/ui/chalkify/bugs/async.rs b/tests/ui/chalkify/bugs/async.rs deleted file mode 100644 index a1ef4732b63..00000000000 --- a/tests/ui/chalkify/bugs/async.rs +++ /dev/null @@ -1,25 +0,0 @@ -// edition:2021 -// known-bug: unknown -// unset-rustc-env:RUST_BACKTRACE -// compile-flags:-Z trait-solver=chalk -// error-pattern:internal compiler error -// failure-status:101 -// normalize-stderr-test "DefId\([^)]*\)" -> "..." -// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> "" -// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> "" -// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" -// normalize-stderr-test "note: compiler flags.*\n\n" -> "" -// normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" -// normalize-stderr-test "thread.*panicked.*\n" -> "" -// normalize-stderr-test "stack backtrace:\n" -> "" -// normalize-stderr-test "\s\d{1,}: .*\n" -> "" -// normalize-stderr-test "\s at .*\n" -> "" -// normalize-stderr-test ".*note: Some details.*\n" -> "" -// normalize-stderr-test "\n\n[ ]*\n" -> "" -// normalize-stderr-test "compiler/.*: projection" -> "projection" - -fn main() -> () {} - -async fn foo(x: u32) -> u32 { - x -} diff --git a/tests/ui/chalkify/bugs/async.stderr b/tests/ui/chalkify/bugs/async.stderr deleted file mode 100644 index 9ebaac31dcb..00000000000 --- a/tests/ui/chalkify/bugs/async.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0277]: `[async fn body@$DIR/async.rs:23:29: 25:2]` is not a future - --> $DIR/async.rs:23:25 - | -LL | async fn foo(x: u32) -> u32 { - | ^^^ `[async fn body@$DIR/async.rs:23:29: 25:2]` is not a future - | - = help: the trait `Future` is not implemented for `[async fn body@$DIR/async.rs:23:29: 25:2]` - = note: [async fn body@$DIR/async.rs:23:29: 25:2] must be a future or must implement `IntoFuture` to be awaited - -error: internal compiler error: projection clauses should be implied from elsewhere. obligation: `Obligation(predicate=Binder { value: ProjectionPredicate(AliasTy { substs: [[async fn body@$DIR/async.rs:23:29: 25:2]], def_id: ... }, Term::Ty(u32)), bound_vars: [] }, depth=0)` - --> $DIR/async.rs:23:25 - | -LL | async fn foo(x: u32) -> u32 { - | ^^^query stack during panic: -#0 [typeck] type-checking `foo` -#1 [type_of] computing type of `foo::{opaque#0}` -#2 [check_mod_item_types] checking item types in top-level module -#3 [analysis] running analysis passes on this crate -end of query stack -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/chalkify/builtin-copy-clone.rs b/tests/ui/chalkify/builtin-copy-clone.rs deleted file mode 100644 index a478c006ef1..00000000000 --- a/tests/ui/chalkify/builtin-copy-clone.rs +++ /dev/null @@ -1,45 +0,0 @@ -// run-pass -// compile-flags: -Z trait-solver=chalk - -// Test that `Clone` is correctly implemented for builtin types. - -#[derive(Copy, Clone)] -struct S(#[allow(unused_tuple_struct_fields)] i32); - -fn test_clone<T: Clone>(arg: T) { - let _ = arg.clone(); -} - -fn test_copy<T: Copy>(arg: T) { - let _ = arg; - let _ = arg; -} - -fn test_copy_clone<T: Copy + Clone>(arg: T) { - test_copy(arg); - test_clone(arg); -} - -fn foo() { } - -fn main() { - // FIXME: add closures when they're considered WF - test_copy_clone(foo); - let f: fn() = foo; - test_copy_clone(f); - // FIXME(#86252): reinstate array test after chalk upgrade - //test_copy_clone([1; 56]); - test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)); - test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, true, 'a', 1.1)); - test_copy_clone(()); - test_copy_clone(((1, 1), (1, 1, 1), (1.1, 1, 1, 'a'), ())); - - let a = ( - (S(1), S(0)), - ( - (S(0), S(0), S(1)), - S(0) - ) - ); - test_copy_clone(a); -} diff --git a/tests/ui/chalkify/chalk_initial_program.rs b/tests/ui/chalkify/chalk_initial_program.rs deleted file mode 100644 index 21de72b6fcc..00000000000 --- a/tests/ui/chalkify/chalk_initial_program.rs +++ /dev/null @@ -1,16 +0,0 @@ -// compile-flags: -Z trait-solver=chalk - -trait Foo { } - -impl Foo for i32 { } - -impl Foo for u32 { } - -fn gimme<F: Foo>() { } - -// Note: this also tests that `std::process::Termination` is implemented for `()`. -fn main() { - gimme::<i32>(); - gimme::<u32>(); - gimme::<f32>(); //~ERROR the trait bound `f32: Foo` is not satisfied -} diff --git a/tests/ui/chalkify/chalk_initial_program.stderr b/tests/ui/chalkify/chalk_initial_program.stderr deleted file mode 100644 index 343c0a31862..00000000000 --- a/tests/ui/chalkify/chalk_initial_program.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0277]: the trait bound `f32: Foo` is not satisfied - --> $DIR/chalk_initial_program.rs:15:13 - | -LL | gimme::<f32>(); - | ^^^ the trait `Foo` is not implemented for `f32` - | - = help: the following other types implement trait `Foo`: - i32 - u32 -note: required by a bound in `gimme` - --> $DIR/chalk_initial_program.rs:9:13 - | -LL | fn gimme<F: Foo>() { } - | ^^^ required by this bound in `gimme` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/chalkify/closure.rs b/tests/ui/chalkify/closure.rs deleted file mode 100644 index a908a1e97ec..00000000000 --- a/tests/ui/chalkify/closure.rs +++ /dev/null @@ -1,38 +0,0 @@ -// compile-flags: -Z trait-solver=chalk - -fn main() -> () { - let t = || {}; - t(); - - let mut a = 0; - let mut b = move || { - a = 1; - }; - b(); - - let mut c = b; - - c(); - b(); - - let mut a = 0; - let mut b = || { - a = 1; - }; - b(); - - let mut c = b; - - c(); - b(); //~ ERROR - - // FIXME(chalk): this doesn't quite work - /* - let b = |c| { - c - }; - - let a = &32; - b(a); - */ -} diff --git a/tests/ui/chalkify/closure.stderr b/tests/ui/chalkify/closure.stderr deleted file mode 100644 index a33c0ba0d37..00000000000 --- a/tests/ui/chalkify/closure.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0382]: borrow of moved value: `b` - --> $DIR/closure.rs:27:5 - | -LL | let mut c = b; - | - value moved here -... -LL | b(); - | ^ value borrowed here after move - | -note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `a` out of its environment - --> $DIR/closure.rs:20:9 - | -LL | a = 1; - | ^ -help: consider mutably borrowing `b` - | -LL | let mut c = &mut b; - | ++++ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/chalkify/generic_impls.rs b/tests/ui/chalkify/generic_impls.rs deleted file mode 100644 index 7d33e12d8be..00000000000 --- a/tests/ui/chalkify/generic_impls.rs +++ /dev/null @@ -1,18 +0,0 @@ -// compile-flags: -Z trait-solver=chalk - -trait Foo { } - -impl<T> Foo for (T, u32) { } - -fn gimme<F: Foo>() { } - -fn foo<T>() { - gimme::<(T, u32)>(); - gimme::<(Option<T>, u32)>(); - gimme::<(Option<T>, f32)>(); //~ ERROR -} - -fn main() { - gimme::<(i32, u32)>(); - gimme::<(i32, f32)>(); //~ ERROR -} diff --git a/tests/ui/chalkify/generic_impls.stderr b/tests/ui/chalkify/generic_impls.stderr deleted file mode 100644 index d4a8354d3fc..00000000000 --- a/tests/ui/chalkify/generic_impls.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error[E0277]: the trait bound `(Option<T>, f32): Foo` is not satisfied - --> $DIR/generic_impls.rs:12:13 - | -LL | gimme::<(Option<T>, f32)>(); - | ^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(Option<T>, f32)` - | - = help: the trait `Foo` is implemented for `(T, u32)` -note: required by a bound in `gimme` - --> $DIR/generic_impls.rs:7:13 - | -LL | fn gimme<F: Foo>() { } - | ^^^ required by this bound in `gimme` - -error[E0277]: the trait bound `(i32, f32): Foo` is not satisfied - --> $DIR/generic_impls.rs:17:13 - | -LL | gimme::<(i32, f32)>(); - | ^^^^^^^^^^ the trait `Foo` is not implemented for `(i32, f32)` - | - = help: the trait `Foo` is implemented for `(T, u32)` -note: required by a bound in `gimme` - --> $DIR/generic_impls.rs:7:13 - | -LL | fn gimme<F: Foo>() { } - | ^^^ required by this bound in `gimme` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/chalkify/impl_wf.rs b/tests/ui/chalkify/impl_wf.rs deleted file mode 100644 index c8dfd4c3a5b..00000000000 --- a/tests/ui/chalkify/impl_wf.rs +++ /dev/null @@ -1,26 +0,0 @@ -// compile-flags: -Z trait-solver=chalk - -trait Foo: Sized { } - -trait Bar { - type Item: Foo; -} - -impl Foo for i32 { } - -impl Foo for str { } -//~^ ERROR the size for values of type `str` cannot be known at compilation time - - -// Implicit `T: Sized` bound. -impl<T> Foo for Option<T> { } - -trait Baz<U: ?Sized> where U: Foo { } - -impl Baz<i32> for i32 { } - -impl Baz<f32> for f32 { } -//~^ ERROR the trait bound `f32: Foo` is not satisfied - -fn main() { -} diff --git a/tests/ui/chalkify/impl_wf.stderr b/tests/ui/chalkify/impl_wf.stderr deleted file mode 100644 index 84c32fa3771..00000000000 --- a/tests/ui/chalkify/impl_wf.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/impl_wf.rs:11:14 - | -LL | impl Foo for str { } - | ^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `str` -note: required by a bound in `Foo` - --> $DIR/impl_wf.rs:3:12 - | -LL | trait Foo: Sized { } - | ^^^^^ required by this bound in `Foo` - -error[E0277]: the trait bound `f32: Foo` is not satisfied - --> $DIR/impl_wf.rs:22:19 - | -LL | impl Baz<f32> for f32 { } - | ^^^ the trait `Foo` is not implemented for `f32` - | - = help: the trait `Foo` is implemented for `i32` -note: required by a bound in `Baz` - --> $DIR/impl_wf.rs:18:31 - | -LL | trait Baz<U: ?Sized> where U: Foo { } - | ^^^ required by this bound in `Baz` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/chalkify/impl_wf_2.rs b/tests/ui/chalkify/impl_wf_2.rs deleted file mode 100644 index 325044ad634..00000000000 --- a/tests/ui/chalkify/impl_wf_2.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Split out of impl_wf.rs to work around rust aborting compilation early - -// compile-flags: -Z trait-solver=chalk - -trait Foo: Sized { } - -trait Bar { - type Item: Foo; -} - -impl Foo for i32 { } - -// Implicit `T: Sized` bound. -impl<T> Foo for Option<T> { } - -impl Bar for () { - type Item = i32; -} - -impl<T> Bar for Option<T> { - type Item = Option<T>; -} - -impl Bar for f32 { - type Item = f32; - //~^ ERROR the trait bound `f32: Foo` is not satisfied -} - -trait Baz<U: ?Sized> where U: Foo { } - -impl Baz<i32> for i32 { } - -fn main() {} diff --git a/tests/ui/chalkify/impl_wf_2.stderr b/tests/ui/chalkify/impl_wf_2.stderr deleted file mode 100644 index 1c1df644b06..00000000000 --- a/tests/ui/chalkify/impl_wf_2.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0277]: the trait bound `f32: Foo` is not satisfied - --> $DIR/impl_wf_2.rs:25:17 - | -LL | type Item = f32; - | ^^^ the trait `Foo` is not implemented for `f32` - | - = help: the trait `Foo` is implemented for `i32` -note: required by a bound in `Bar::Item` - --> $DIR/impl_wf_2.rs:8:16 - | -LL | type Item: Foo; - | ^^^ required by this bound in `Bar::Item` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/chalkify/inherent_impl.rs b/tests/ui/chalkify/inherent_impl.rs deleted file mode 100644 index f0f24d485cd..00000000000 --- a/tests/ui/chalkify/inherent_impl.rs +++ /dev/null @@ -1,42 +0,0 @@ -// run-pass -// compile-flags: -Z trait-solver=chalk - -trait Foo { } - -impl Foo for i32 { } - -struct S<T: Foo> { - x: T, -} - -fn only_foo<T: Foo>(_x: &T) { } - -impl<T> S<T> { - // Test that we have the correct environment inside an inherent method. - fn dummy_foo(&self) { - only_foo(&self.x) - } -} - -trait Bar { } -impl Bar for u32 { } - -fn only_bar<T: Bar>() { } - -impl<T> S<T> { - // Test that the environment of `dummy_bar` adds up with the environment - // of the inherent impl. - fn dummy_bar<U: Bar>(&self) { - only_foo(&self.x); - only_bar::<U>(); - } -} - -fn main() { - let s = S { - x: 5, - }; - - s.dummy_bar::<u32>(); - s.dummy_foo(); -} diff --git a/tests/ui/chalkify/inherent_impl_min.rs b/tests/ui/chalkify/inherent_impl_min.rs deleted file mode 100644 index 3eda7102dec..00000000000 --- a/tests/ui/chalkify/inherent_impl_min.rs +++ /dev/null @@ -1,27 +0,0 @@ -// run-pass -// compile-flags: -Z trait-solver=chalk - -trait Foo { } - -impl Foo for i32 { } - -struct S<T: Foo> { - x: T, -} - -fn only_foo<T: Foo>(_x: &T) { } - -impl<T> S<T> { - // Test that we have the correct environment inside an inherent method. - fn dummy_foo(&self) { - only_foo(&self.x) - } -} - -fn main() { - let s = S { - x: 5, - }; - - s.dummy_foo(); -} diff --git a/tests/ui/chalkify/lower_env1.rs b/tests/ui/chalkify/lower_env1.rs deleted file mode 100644 index c8762001e6a..00000000000 --- a/tests/ui/chalkify/lower_env1.rs +++ /dev/null @@ -1,14 +0,0 @@ -// check-pass -// compile-flags: -Z trait-solver=chalk - -#![allow(dead_code)] - -trait Foo { } - -trait Bar where Self: Foo { } - -fn bar<T: Bar + ?Sized>() { -} - -fn main() { -} diff --git a/tests/ui/chalkify/lower_env2.rs b/tests/ui/chalkify/lower_env2.rs deleted file mode 100644 index 7d4f81f12ea..00000000000 --- a/tests/ui/chalkify/lower_env2.rs +++ /dev/null @@ -1,16 +0,0 @@ -// check-pass -// compile-flags: -Z trait-solver=chalk - -#![allow(dead_code)] - -trait Foo { } - -struct S<'a, T: ?Sized> where T: Foo { - data: &'a T, -} - -fn bar<T: Foo>(_x: S<'_, T>) { // note that we have an implicit `T: Sized` bound -} - -fn main() { -} diff --git a/tests/ui/chalkify/lower_env3.rs b/tests/ui/chalkify/lower_env3.rs deleted file mode 100644 index 5b70c4abbb5..00000000000 --- a/tests/ui/chalkify/lower_env3.rs +++ /dev/null @@ -1,16 +0,0 @@ -// check-pass -// compile-flags: -Z trait-solver=chalk - -#![allow(dead_code)] - -trait Foo { - fn foo(&self); -} - -impl<T> Foo for T where T: Clone { - fn foo(&self) { - } -} - -fn main() { -} diff --git a/tests/ui/chalkify/lower_impl.rs b/tests/ui/chalkify/lower_impl.rs deleted file mode 100644 index 6f79b3ba386..00000000000 --- a/tests/ui/chalkify/lower_impl.rs +++ /dev/null @@ -1,17 +0,0 @@ -// check-pass -// compile-flags: -Z trait-solver=chalk - -trait Foo { } - -impl<T: 'static> Foo for T where T: Iterator<Item = i32> { } - -trait Bar { - type Assoc; -} - -impl<T> Bar for T where T: Iterator<Item = i32> { - type Assoc = Vec<T>; -} - -fn main() { -} diff --git a/tests/ui/chalkify/lower_struct.rs b/tests/ui/chalkify/lower_struct.rs deleted file mode 100644 index 6be0d4dd5bd..00000000000 --- a/tests/ui/chalkify/lower_struct.rs +++ /dev/null @@ -1,8 +0,0 @@ -// check-pass -// compile-flags: -Z trait-solver=chalk - -struct Foo<'a, T> where Box<T>: Clone { - _x: std::marker::PhantomData<&'a T>, -} - -fn main() { } diff --git a/tests/ui/chalkify/lower_trait.rs b/tests/ui/chalkify/lower_trait.rs deleted file mode 100644 index 8f5b358220b..00000000000 --- a/tests/ui/chalkify/lower_trait.rs +++ /dev/null @@ -1,11 +0,0 @@ -// check-pass -// compile-flags: -Z trait-solver=chalk - -trait Bar { } - -trait Foo<S, T: ?Sized> { - type Assoc: Bar + ?Sized; -} - -fn main() { -} diff --git a/tests/ui/chalkify/lower_trait_higher_rank.rs b/tests/ui/chalkify/lower_trait_higher_rank.rs deleted file mode 100644 index f04a1deea87..00000000000 --- a/tests/ui/chalkify/lower_trait_higher_rank.rs +++ /dev/null @@ -1,9 +0,0 @@ -// check-pass -// compile-flags: -Z trait-solver=chalk - -trait Foo<F: ?Sized> where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8 -{ -} - -fn main() { -} diff --git a/tests/ui/chalkify/lower_trait_where_clause.rs b/tests/ui/chalkify/lower_trait_where_clause.rs deleted file mode 100644 index a21d2f31963..00000000000 --- a/tests/ui/chalkify/lower_trait_where_clause.rs +++ /dev/null @@ -1,16 +0,0 @@ -// check-pass -// compile-flags: -Z trait-solver=chalk - -use std::borrow::Borrow; - -trait Foo<'a, 'b, T, U> -where - T: Borrow<U> + ?Sized, - U: ?Sized + 'b, - 'a: 'b, - Box<T>:, // NOTE(#53696) this checks an empty list of bounds. -{ -} - -fn main() { -} diff --git a/tests/ui/chalkify/println.rs b/tests/ui/chalkify/println.rs deleted file mode 100644 index edddc382152..00000000000 --- a/tests/ui/chalkify/println.rs +++ /dev/null @@ -1,6 +0,0 @@ -// check-pass -// compile-flags: -Z trait-solver=chalk - -fn main() { - println!("hello"); -} diff --git a/tests/ui/chalkify/projection.rs b/tests/ui/chalkify/projection.rs deleted file mode 100644 index 19bb2ae1497..00000000000 --- a/tests/ui/chalkify/projection.rs +++ /dev/null @@ -1,25 +0,0 @@ -// run-pass -// compile-flags: -Z trait-solver=chalk - -trait Foo { } - -trait Bar { - type Item: Foo; -} - -impl Foo for i32 { } -impl Bar for i32 { - type Item = i32; -} - -fn only_foo<T: Foo>() { } - -fn only_bar<T: Bar>() { - // `T` implements `Bar` hence `<T as Bar>::Item` must also implement `Bar` - only_foo::<T::Item>() -} - -fn main() { - only_bar::<i32>(); - only_foo::<<i32 as Bar>::Item>(); -} diff --git a/tests/ui/chalkify/recursive_where_clause_on_type.rs b/tests/ui/chalkify/recursive_where_clause_on_type.rs deleted file mode 100644 index c2c8aa6aabe..00000000000 --- a/tests/ui/chalkify/recursive_where_clause_on_type.rs +++ /dev/null @@ -1,30 +0,0 @@ -// FIXME(chalk): should fail, see comments -// check-fail -// compile-flags: -Z trait-solver=chalk - -#![feature(trivial_bounds)] - -trait Bar { - fn foo(); -} -trait Foo: Bar { } - -struct S where S: Foo; - -impl Foo for S { -} - -fn bar<T: Bar>() { - T::foo(); -} - -fn foo<T: Foo>() { - bar::<T>() -} - -fn main() { - // For some reason, the error is duplicated... - - foo::<S>() //~ ERROR the type `S` is not well-formed - //~^ ERROR the type `S` is not well-formed -} diff --git a/tests/ui/chalkify/recursive_where_clause_on_type.stderr b/tests/ui/chalkify/recursive_where_clause_on_type.stderr deleted file mode 100644 index cead5adeaaa..00000000000 --- a/tests/ui/chalkify/recursive_where_clause_on_type.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: the type `S` is not well-formed - --> $DIR/recursive_where_clause_on_type.rs:28:11 - | -LL | foo::<S>() - | ^ - -error: the type `S` is not well-formed - --> $DIR/recursive_where_clause_on_type.rs:28:5 - | -LL | foo::<S>() - | ^^^^^^^^ - -error: aborting due to 2 previous errors - diff --git a/tests/ui/chalkify/super_trait.rs b/tests/ui/chalkify/super_trait.rs deleted file mode 100644 index 540ae51e57f..00000000000 --- a/tests/ui/chalkify/super_trait.rs +++ /dev/null @@ -1,19 +0,0 @@ -// run-pass -// compile-flags: -Z trait-solver=chalk - -trait Foo { } -trait Bar: Foo { } - -impl Foo for i32 { } -impl Bar for i32 { } - -fn only_foo<T: Foo>() { } - -fn only_bar<T: Bar>() { - // `T` implements `Bar` hence `T` must also implement `Foo` - only_foo::<T>() -} - -fn main() { - only_bar::<i32>() -} diff --git a/tests/ui/chalkify/trait-objects.rs b/tests/ui/chalkify/trait-objects.rs deleted file mode 100644 index 144d9788b82..00000000000 --- a/tests/ui/chalkify/trait-objects.rs +++ /dev/null @@ -1,12 +0,0 @@ -// check-pass -// compile-flags: -Z trait-solver=chalk - -use std::fmt::Display; - -fn main() { - let d: &dyn Display = &mut 3; - d.to_string(); - (&d).to_string(); - let f: &dyn Fn(i32) -> _ = &|x| x + x; - f(2); -} diff --git a/tests/ui/chalkify/trait_implied_bound.rs b/tests/ui/chalkify/trait_implied_bound.rs deleted file mode 100644 index f97dbf6b7e7..00000000000 --- a/tests/ui/chalkify/trait_implied_bound.rs +++ /dev/null @@ -1,18 +0,0 @@ -// run-pass -// compile-flags: -Z trait-solver=chalk - -trait Foo { } -trait Bar<U> where U: Foo { } - -impl Foo for i32 { } -impl Bar<i32> for i32 { } - -fn only_foo<T: Foo>() { } - -fn only_bar<U, T: Bar<U>>() { - only_foo::<U>() -} - -fn main() { - only_bar::<i32, i32>() -} diff --git a/tests/ui/chalkify/type_implied_bound.rs b/tests/ui/chalkify/type_implied_bound.rs deleted file mode 100644 index 70f1b4265e4..00000000000 --- a/tests/ui/chalkify/type_implied_bound.rs +++ /dev/null @@ -1,29 +0,0 @@ -// run-pass -// compile-flags: -Z trait-solver=chalk - -trait Eq { } -trait Hash: Eq { } - -impl Eq for i32 { } -impl Hash for i32 { } - -struct Set<T: Hash> { - _x: T, -} - -fn only_eq<T: Eq>() { } - -fn take_a_set<T>(_: &Set<T>) { - // `Set<T>` is an input type of `take_a_set`, hence we know that - // `T` must implement `Hash`, and we know in turn that `T` must - // implement `Eq`. - only_eq::<T>() -} - -fn main() { - let set = Set { - _x: 5, - }; - - take_a_set(&set); -} diff --git a/tests/ui/chalkify/type_inference.rs b/tests/ui/chalkify/type_inference.rs deleted file mode 100644 index d7167d0dc57..00000000000 --- a/tests/ui/chalkify/type_inference.rs +++ /dev/null @@ -1,28 +0,0 @@ -// compile-flags: -Z trait-solver=chalk - -trait Foo { } -impl Foo for i32 { } - -trait Bar { } -impl Bar for i32 { } -impl Bar for u32 { } - -fn only_foo<T: Foo>(_x: T) { } - -fn only_bar<T: Bar>(_x: T) { } - -fn main() { - let x = 5.0; - - // The only type which implements `Foo` is `i32`, so the chalk trait solver - // is expecting a variable of type `i32`. This behavior differs from the - // old-style trait solver. I guess this will change, that's why I'm - // adding that test. - // FIXME(chalk): order of these two errors is non-deterministic, - // so let's just hide one for now - //only_foo(x); // ERROR the trait bound `f64: Foo` is not satisfied - - // Here we have two solutions so we get back the behavior of the old-style - // trait solver. - only_bar(x); //~ ERROR the trait bound `{float}: Bar` is not satisfied -} diff --git a/tests/ui/chalkify/type_inference.stderr b/tests/ui/chalkify/type_inference.stderr deleted file mode 100644 index 508a6dd1388..00000000000 --- a/tests/ui/chalkify/type_inference.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0277]: the trait bound `{float}: Bar` is not satisfied - --> $DIR/type_inference.rs:27:14 - | -LL | only_bar(x); - | -------- ^ the trait `Bar` is not implemented for `{float}` - | | - | required by a bound introduced by this call - | - = help: the following other types implement trait `Bar`: - i32 - u32 -note: required by a bound in `only_bar` - --> $DIR/type_inference.rs:12:16 - | -LL | fn only_bar<T: Bar>(_x: T) { } - | ^^^ required by this bound in `only_bar` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/chalkify/type_wf.rs b/tests/ui/chalkify/type_wf.rs deleted file mode 100644 index 37d2f5ca832..00000000000 --- a/tests/ui/chalkify/type_wf.rs +++ /dev/null @@ -1,25 +0,0 @@ -// check-fail -// compile-flags: -Z trait-solver=chalk - -trait Foo { } - -struct S<T: Foo> { - x: T, -} - -impl Foo for i32 { } -impl<T> Foo for Option<T> { } - -fn main() { - let s = S { - x: 5, - }; - - let s = S { - x: 5.0, //~ ERROR the trait bound `{float}: Foo` is not satisfied - }; - - let s = S { - x: Some(5.0), - }; -} diff --git a/tests/ui/chalkify/type_wf.stderr b/tests/ui/chalkify/type_wf.stderr deleted file mode 100644 index 6e8daf63517..00000000000 --- a/tests/ui/chalkify/type_wf.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0277]: the trait bound `{float}: Foo` is not satisfied - --> $DIR/type_wf.rs:19:12 - | -LL | x: 5.0, - | ^^^ the trait `Foo` is not implemented for `{float}` - | - = help: the trait `Foo` is implemented for `i32` -note: required by a bound in `S` - --> $DIR/type_wf.rs:6:13 - | -LL | struct S<T: Foo> { - | ^^^ required by this bound in `S` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/const-generics/defaults/default-param-wf-concrete.stderr b/tests/ui/const-generics/defaults/default-param-wf-concrete.next.stderr index e8ebddade5c..4259ce2b626 100644 --- a/tests/ui/const-generics/defaults/default-param-wf-concrete.stderr +++ b/tests/ui/const-generics/defaults/default-param-wf-concrete.next.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation of constant value failed - --> $DIR/default-param-wf-concrete.rs:1:28 + --> $DIR/default-param-wf-concrete.rs:4:28 | LL | struct Foo<const N: u8 = { 255 + 1 }>; | ^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow diff --git a/tests/ui/const-generics/defaults/default-param-wf-concrete.old.stderr b/tests/ui/const-generics/defaults/default-param-wf-concrete.old.stderr new file mode 100644 index 00000000000..4259ce2b626 --- /dev/null +++ b/tests/ui/const-generics/defaults/default-param-wf-concrete.old.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/default-param-wf-concrete.rs:4:28 + | +LL | struct Foo<const N: u8 = { 255 + 1 }>; + | ^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/const-generics/defaults/default-param-wf-concrete.rs b/tests/ui/const-generics/defaults/default-param-wf-concrete.rs index 41a52c7eb0d..09a00dd8e70 100644 --- a/tests/ui/const-generics/defaults/default-param-wf-concrete.rs +++ b/tests/ui/const-generics/defaults/default-param-wf-concrete.rs @@ -1,3 +1,6 @@ +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next + struct Foo<const N: u8 = { 255 + 1 }>; //~^ ERROR evaluation of constant value failed fn main() {} diff --git a/tests/ui/consts/const-len-underflow-separate-spans.stderr b/tests/ui/consts/const-len-underflow-separate-spans.next.stderr index 269553631cc..d9208d0706a 100644 --- a/tests/ui/consts/const-len-underflow-separate-spans.stderr +++ b/tests/ui/consts/const-len-underflow-separate-spans.next.stderr @@ -1,11 +1,11 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const-len-underflow-separate-spans.rs:7:20 + --> $DIR/const-len-underflow-separate-spans.rs:10:20 | LL | const LEN: usize = ONE - TWO; | ^^^^^^^^^ attempt to compute `1_usize - 2_usize`, which would overflow note: erroneous constant used - --> $DIR/const-len-underflow-separate-spans.rs:11:17 + --> $DIR/const-len-underflow-separate-spans.rs:14:17 | LL | let a: [i8; LEN] = unimplemented!(); | ^^^ diff --git a/tests/ui/consts/const-len-underflow-separate-spans.old.stderr b/tests/ui/consts/const-len-underflow-separate-spans.old.stderr new file mode 100644 index 00000000000..d9208d0706a --- /dev/null +++ b/tests/ui/consts/const-len-underflow-separate-spans.old.stderr @@ -0,0 +1,15 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-len-underflow-separate-spans.rs:10:20 + | +LL | const LEN: usize = ONE - TWO; + | ^^^^^^^^^ attempt to compute `1_usize - 2_usize`, which would overflow + +note: erroneous constant used + --> $DIR/const-len-underflow-separate-spans.rs:14:17 + | +LL | let a: [i8; LEN] = unimplemented!(); + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-len-underflow-separate-spans.rs b/tests/ui/consts/const-len-underflow-separate-spans.rs index 4544c8876ae..55704b64154 100644 --- a/tests/ui/consts/const-len-underflow-separate-spans.rs +++ b/tests/ui/consts/const-len-underflow-separate-spans.rs @@ -2,6 +2,9 @@ // spot (where the underflow occurred), while also providing the // overall context for what caused the evaluation. +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next + const ONE: usize = 1; const TWO: usize = 2; const LEN: usize = ONE - TWO; diff --git a/tests/ui/duplicate/dupe-symbols-7.rs b/tests/ui/duplicate/dupe-symbols-7.rs index 633ca4c3189..4983874729c 100644 --- a/tests/ui/duplicate/dupe-symbols-7.rs +++ b/tests/ui/duplicate/dupe-symbols-7.rs @@ -3,9 +3,6 @@ // // error-pattern: entry symbol `main` declared multiple times -// FIXME https://github.com/rust-lang/rust/issues/59774 -// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" -// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" #![allow(warnings)] #[no_mangle] diff --git a/tests/ui/duplicate/dupe-symbols-7.stderr b/tests/ui/duplicate/dupe-symbols-7.stderr index 1455f0e75ab..cd5147c0e15 100644 --- a/tests/ui/duplicate/dupe-symbols-7.stderr +++ b/tests/ui/duplicate/dupe-symbols-7.stderr @@ -1,5 +1,5 @@ error: entry symbol `main` declared multiple times - --> $DIR/dupe-symbols-7.rs:12:1 + --> $DIR/dupe-symbols-7.rs:9:1 | LL | fn main(){} | ^^^^^^^^^ diff --git a/tests/ui/dyn-star/box.rs b/tests/ui/dyn-star/box.rs index d1f1819d9f3..87c8356a174 100644 --- a/tests/ui/dyn-star/box.rs +++ b/tests/ui/dyn-star/box.rs @@ -1,5 +1,7 @@ // run-pass -// compile-flags: -C opt-level=0 +// revisions: current next +//[current] compile-flags: -C opt-level=0 +//[next] compile-flags: -Ztrait-solver=next -C opt-level=0 #![feature(dyn_star)] #![allow(incomplete_features)] diff --git a/tests/ui/dyn-star/param-env-infer.current.stderr b/tests/ui/dyn-star/param-env-infer.current.stderr deleted file mode 100644 index b3af7be7950..00000000000 --- a/tests/ui/dyn-star/param-env-infer.current.stderr +++ /dev/null @@ -1,18 +0,0 @@ -warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/param-env-infer.rs:5:12 - | -LL | #![feature(dyn_star, pointer_like_trait)] - | ^^^^^^^^ - | - = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information - = note: `#[warn(incomplete_features)]` on by default - -error[E0282]: type annotations needed - --> $DIR/param-env-infer.rs:13:10 - | -LL | t as _ - | ^ cannot infer type - -error: aborting due to previous error; 1 warning emitted - -For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/dyn-star/param-env-infer.next.stderr b/tests/ui/dyn-star/param-env-infer.next.stderr deleted file mode 100644 index 408abecc30d..00000000000 --- a/tests/ui/dyn-star/param-env-infer.next.stderr +++ /dev/null @@ -1,38 +0,0 @@ -warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/param-env-infer.rs:5:12 - | -LL | #![feature(dyn_star, pointer_like_trait)] - | ^^^^^^^^ - | - = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information - = note: `#[warn(incomplete_features)]` on by default - -error[E0391]: cycle detected when computing type of `make_dyn_star::{opaque#0}` - --> $DIR/param-env-infer.rs:11:60 - | -LL | fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires type-checking `make_dyn_star`... - --> $DIR/param-env-infer.rs:11:1 - | -LL | fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which requires computing layout of `make_dyn_star::{opaque#0}`... - = note: ...which requires normalizing `make_dyn_star::{opaque#0}`... - = note: ...which again requires computing type of `make_dyn_star::{opaque#0}`, completing the cycle -note: cycle used when checking item types in top-level module - --> $DIR/param-env-infer.rs:5:1 - | -LL | / #![feature(dyn_star, pointer_like_trait)] -LL | | -LL | | -LL | | use std::fmt::Debug; -... | -LL | | -LL | | fn main() {} - | |____________^ - -error: aborting due to previous error; 1 warning emitted - -For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/dyn-star/param-env-region-infer.current.stderr b/tests/ui/dyn-star/param-env-region-infer.current.stderr new file mode 100644 index 00000000000..c606a50c8a9 --- /dev/null +++ b/tests/ui/dyn-star/param-env-region-infer.current.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/param-env-region-infer.rs:16:10 + | +LL | t as _ + | ^ cannot infer type + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/dyn-star/param-env-infer.rs b/tests/ui/dyn-star/param-env-region-infer.rs index 1fb16d76853..9c337e4a89b 100644 --- a/tests/ui/dyn-star/param-env-infer.rs +++ b/tests/ui/dyn-star/param-env-region-infer.rs @@ -1,15 +1,18 @@ // revisions: current next //[next] compile-flags: -Ztrait-solver=next +//[next] check-pass // incremental +// checks that we don't ICE if there are region inference variables in the environment +// when computing `PointerLike` builtin candidates. + #![feature(dyn_star, pointer_like_trait)] -//~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes +#![allow(incomplete_features)] use std::fmt::Debug; use std::marker::PointerLike; fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a { - //[next]~^ ERROR cycle detected when computing type of `make_dyn_star::{opaque#0}` t as _ //[current]~^ ERROR type annotations needed } diff --git a/tests/ui/feature-gates/feature-gate-type_alias_impl_trait.rs b/tests/ui/feature-gates/feature-gate-type_alias_impl_trait.rs index 6dfd7f6840f..0d019b1f502 100644 --- a/tests/ui/feature-gates/feature-gate-type_alias_impl_trait.rs +++ b/tests/ui/feature-gates/feature-gate-type_alias_impl_trait.rs @@ -1,4 +1,3 @@ -// ignore-compare-mode-chalk // check-pass #![feature(type_alias_impl_trait)] use std::fmt::Debug; diff --git a/tests/ui/for/issue-20605.next.stderr b/tests/ui/for/issue-20605.next.stderr index a96a53ca93e..d55efedfcbe 100644 --- a/tests/ui/for/issue-20605.next.stderr +++ b/tests/ui/for/issue-20605.next.stderr @@ -20,6 +20,53 @@ error: the type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is LL | for item in *things { *item = 0 } | ^^^^^^^ -error: aborting due to 3 previous errors +error[E0277]: `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not an iterator + --> $DIR/issue-20605.rs:5:17 + | +LL | for item in *things { *item = 0 } + | ^^^^^^^ `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not an iterator + | + = help: the trait `Iterator` is not implemented for `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` + +error: the type `&mut <dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed + --> $DIR/issue-20605.rs:5:17 + | +LL | for item in *things { *item = 0 } + | ^^^^^^^ + +error[E0614]: type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be dereferenced + --> $DIR/issue-20605.rs:5:27 + | +LL | for item in *things { *item = 0 } + | ^^^^^ + +error[E0277]: the size for values of type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be known at compilation time + --> $DIR/issue-20605.rs:5:9 + | +LL | for item in *things { *item = 0 } + | ^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + +error: the type `Option<<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item>` is not well-formed + --> $DIR/issue-20605.rs:5:17 + | +LL | for item in *things { *item = 0 } + | ^^^^^^^ + +error[E0277]: the size for values of type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be known at compilation time + --> $DIR/issue-20605.rs:5:5 + | +LL | for item in *things { *item = 0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` +note: required by a bound in `None` + --> $SRC_DIR/core/src/option.rs:LL:COL + +error: aborting due to 9 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0614. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/for/issue-20605.rs b/tests/ui/for/issue-20605.rs index 64156b35705..50d4c3fddb5 100644 --- a/tests/ui/for/issue-20605.rs +++ b/tests/ui/for/issue-20605.rs @@ -3,9 +3,18 @@ fn changer<'a>(mut things: Box<dyn Iterator<Item=&'a mut u8>>) { for item in *things { *item = 0 } - //~^ ERROR the size for values of type - //[next]~^^ ERROR the type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed - //[next]~| ERROR the trait bound `dyn Iterator<Item = &'a mut u8>: IntoIterator` is not satisfied + //[current]~^ ERROR the size for values of type + //[next]~^^ ERROR the trait bound `dyn Iterator<Item = &'a mut u8>: IntoIterator` is not satisfied + //[next]~| ERROR the size for values of type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` cannot be known at compilation time + //[next]~| ERROR the type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed + //[next]~| ERROR `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not an iterator + //[next]~| ERROR the type `&mut <dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed + //[next]~| ERROR the size for values of type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be known at compilation time + //[next]~| ERROR the type `Option<<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item>` is not well-formed + //[next]~| ERROR the size for values of type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be known at compilation time + //[next]~| ERROR type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be dereferenced + // FIXME(-Ztrait-solver=next): these error messages are horrible and have to be + // improved before we stabilize the new solver. } fn main() {} diff --git a/tests/ui/generator/layout-error.rs b/tests/ui/generator/layout-error.rs index 7c3d187409a..44cfc1d70dd 100644 --- a/tests/ui/generator/layout-error.rs +++ b/tests/ui/generator/layout-error.rs @@ -24,5 +24,6 @@ fn main() { type F = impl Future; // Check that statics are inhabited computes they layout. static POOL: Task<F> = Task::new(); + //~^ ERROR: cannot check whether the hidden type of `layout_error[b009]::main::F::{opaque#0}` satisfies auto traits Task::spawn(&POOL, || cb()); } diff --git a/tests/ui/generator/layout-error.stderr b/tests/ui/generator/layout-error.stderr index b1a258f4f2c..ea3b25551c4 100644 --- a/tests/ui/generator/layout-error.stderr +++ b/tests/ui/generator/layout-error.stderr @@ -4,6 +4,24 @@ error[E0425]: cannot find value `Foo` in this scope LL | let a = Foo; | ^^^ not found in this scope -error: aborting due to previous error +error: cannot check whether the hidden type of `layout_error[b009]::main::F::{opaque#0}` satisfies auto traits + --> $DIR/layout-error.rs:26:18 + | +LL | static POOL: Task<F> = Task::new(); + | ^^^^^^^ + | +note: opaque type is declared here + --> $DIR/layout-error.rs:24:14 + | +LL | type F = impl Future; + | ^^^^^^^^^^^ +note: required because it appears within the type `Task<F>` + --> $DIR/layout-error.rs:9:12 + | +LL | pub struct Task<F: Future>(F); + | ^^^^ + = note: shared static variables must have a type that implements `Sync` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/generic-associated-types/gat-bounds-not-checked-with-right-substitutions.rs b/tests/ui/generic-associated-types/gat-bounds-not-checked-with-right-substitutions.rs new file mode 100644 index 00000000000..05d205266b4 --- /dev/null +++ b/tests/ui/generic-associated-types/gat-bounds-not-checked-with-right-substitutions.rs @@ -0,0 +1,29 @@ +// This test checks that we correctly reject the following unsound code. + +trait Lengthen<T> { + fn lengthen(self) -> T; +} + +impl<'a> Lengthen<&'a str> for &'a str { + fn lengthen(self) -> &'a str { self } +} + +trait Gat { + type Gat<'a>: for<'b> Lengthen<Self::Gat<'b>>; + + fn lengthen(s: Self::Gat<'_>) -> Self::Gat<'static> { + s.lengthen() + } +} + +impl Gat for () { + type Gat<'a> = &'a str; //~ ERROR: implementation of `Lengthen` is not general enough +} + +fn main() { + let s = "hello, garbage".to_string(); + let borrow: &'static str = <() as Gat>::lengthen(&s); + drop(s); + + println!("{borrow}"); +} diff --git a/tests/ui/generic-associated-types/gat-bounds-not-checked-with-right-substitutions.stderr b/tests/ui/generic-associated-types/gat-bounds-not-checked-with-right-substitutions.stderr new file mode 100644 index 00000000000..7ea7a7b2de7 --- /dev/null +++ b/tests/ui/generic-associated-types/gat-bounds-not-checked-with-right-substitutions.stderr @@ -0,0 +1,11 @@ +error: implementation of `Lengthen` is not general enough + --> $DIR/gat-bounds-not-checked-with-right-substitutions.rs:20:20 + | +LL | type Gat<'a> = &'a str; + | ^^^^^^^ implementation of `Lengthen` is not general enough + | + = note: `Lengthen<&'0 str>` would have to be implemented for the type `&'a str`, for any lifetime `'0`... + = note: ...but `Lengthen<&'1 str>` is actually implemented for the type `&'1 str`, for some specific lifetime `'1` + +error: aborting due to previous error + diff --git a/tests/ui/hashmap/hashmap-memory.rs b/tests/ui/hashmap/hashmap-memory.rs index 87f8b6ad573..bd364b349e2 100644 --- a/tests/ui/hashmap/hashmap-memory.rs +++ b/tests/ui/hashmap/hashmap-memory.rs @@ -1,5 +1,6 @@ // run-pass +#![allow(improper_ctypes_definitions)] #![allow(non_camel_case_types)] #![allow(dead_code)] #![allow(unused_mut)] diff --git a/tests/ui/impl-trait/auto-trait-leak.rs b/tests/ui/impl-trait/auto-trait-leak.rs index c2fbbf94fd6..d71c0987935 100644 --- a/tests/ui/impl-trait/auto-trait-leak.rs +++ b/tests/ui/impl-trait/auto-trait-leak.rs @@ -3,21 +3,23 @@ use std::rc::Rc; fn send<T: Send>(_: T) {} -fn main() { -} +fn main() {} // Cycles should work as the deferred obligations are // independently resolved and only require the concrete // return type, which can't depend on the obligation. fn cycle1() -> impl Clone { //~^ ERROR cycle detected + //~| ERROR cycle detected send(cycle2().clone()); + //~^ ERROR: cannot check whether the hidden type of opaque type satisfies auto traits Rc::new(Cell::new(5)) } fn cycle2() -> impl Clone { send(cycle1().clone()); + //~^ ERROR: cannot check whether the hidden type of opaque type satisfies auto traits Rc::new(String::from("foo")) } diff --git a/tests/ui/impl-trait/auto-trait-leak.stderr b/tests/ui/impl-trait/auto-trait-leak.stderr index c0c4cd5013e..92a9763bc9b 100644 --- a/tests/ui/impl-trait/auto-trait-leak.stderr +++ b/tests/ui/impl-trait/auto-trait-leak.stderr @@ -1,5 +1,5 @@ error[E0391]: cycle detected when computing type of `cycle1::{opaque#0}` - --> $DIR/auto-trait-leak.rs:12:16 + --> $DIR/auto-trait-leak.rs:11:16 | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^ @@ -11,12 +11,12 @@ LL | send(cycle2().clone()); | ^^^^ = note: ...which requires evaluating trait selection obligation `cycle2::{opaque#0}: core::marker::Send`... note: ...which requires computing type of `cycle2::{opaque#0}`... - --> $DIR/auto-trait-leak.rs:19:16 + --> $DIR/auto-trait-leak.rs:20:16 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ note: ...which requires type-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:20:5 + --> $DIR/auto-trait-leak.rs:21:5 | LL | send(cycle1().clone()); | ^^^^ @@ -34,6 +34,89 @@ LL | | Rc::new(String::from("foo")) LL | | } | |_^ -error: aborting due to previous error +error[E0391]: cycle detected when computing type of `cycle1::{opaque#0}` + --> $DIR/auto-trait-leak.rs:11:16 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^ + | +note: ...which requires type-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:14:5 + | +LL | send(cycle2().clone()); + | ^^^^ + = note: ...which requires evaluating trait selection obligation `cycle2::{opaque#0}: core::marker::Send`... +note: ...which requires computing type of `cycle2::{opaque#0}`... + --> $DIR/auto-trait-leak.rs:20:16 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^ +note: ...which requires type-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:20:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle +note: cycle used when checking item types in top-level module + --> $DIR/auto-trait-leak.rs:1:1 + | +LL | / use std::cell::Cell; +LL | | use std::rc::Rc; +LL | | +LL | | fn send<T: Send>(_: T) {} +... | +LL | | Rc::new(String::from("foo")) +LL | | } + | |_^ + +error: cannot check whether the hidden type of opaque type satisfies auto traits + --> $DIR/auto-trait-leak.rs:21:10 + | +LL | send(cycle1().clone()); + | ---- ^^^^^^^^^^^^^^^^ + | | + | required by a bound introduced by this call + | +note: opaque type is declared here + --> $DIR/auto-trait-leak.rs:11:16 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^ +note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule + --> $DIR/auto-trait-leak.rs:20:4 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^ +note: required by a bound in `send` + --> $DIR/auto-trait-leak.rs:4:12 + | +LL | fn send<T: Send>(_: T) {} + | ^^^^ required by this bound in `send` + +error: cannot check whether the hidden type of opaque type satisfies auto traits + --> $DIR/auto-trait-leak.rs:14:10 + | +LL | send(cycle2().clone()); + | ---- ^^^^^^^^^^^^^^^^ + | | + | required by a bound introduced by this call + | +note: opaque type is declared here + --> $DIR/auto-trait-leak.rs:20:16 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^ +note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule + --> $DIR/auto-trait-leak.rs:11:4 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^ +note: required by a bound in `send` + --> $DIR/auto-trait-leak.rs:4:12 + | +LL | fn send<T: Send>(_: T) {} + | ^^^^ required by this bound in `send` + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/impl-trait/in-trait/issue-102140.next.stderr b/tests/ui/impl-trait/in-trait/issue-102140.next.stderr index 7aa7880e258..94893c9e7b4 100644 --- a/tests/ui/impl-trait/in-trait/issue-102140.next.stderr +++ b/tests/ui/impl-trait/in-trait/issue-102140.next.stderr @@ -6,11 +6,7 @@ LL | MyTrait::foo(&self) | | | required by a bound introduced by this call | -help: consider removing the leading `&`-reference - | -LL - MyTrait::foo(&self) -LL + MyTrait::foo(self) - | + = help: the trait `MyTrait` is implemented for `Outer` error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied --> $DIR/issue-102140.rs:26:9 diff --git a/tests/ui/impl-trait/in-trait/wf-bounds.current.stderr b/tests/ui/impl-trait/in-trait/wf-bounds.current.stderr index 1a70716123c..74c84c012b1 100644 --- a/tests/ui/impl-trait/in-trait/wf-bounds.current.stderr +++ b/tests/ui/impl-trait/in-trait/wf-bounds.current.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/wf-bounds.rs:13:22 + --> $DIR/wf-bounds.rs:17:22 | LL | fn nya() -> impl Wf<Vec<[u8]>>; | ^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -9,14 +9,14 @@ note: required by a bound in `Vec` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/wf-bounds.rs:16:23 + --> $DIR/wf-bounds.rs:20:23 | LL | fn nya2() -> impl Wf<[u8]>; | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `Wf` - --> $DIR/wf-bounds.rs:8:10 + --> $DIR/wf-bounds.rs:10:10 | LL | trait Wf<T> { | ^ required by this bound in `Wf` @@ -26,7 +26,7 @@ LL | trait Wf<T: ?Sized> { | ++++++++ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/wf-bounds.rs:19:44 + --> $DIR/wf-bounds.rs:23:44 | LL | fn nya3() -> impl Wf<(), Output = impl Wf<Vec<[u8]>>>; | ^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -35,6 +35,23 @@ LL | fn nya3() -> impl Wf<(), Output = impl Wf<Vec<[u8]>>>; note: required by a bound in `Vec` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -error: aborting due to 3 previous errors +error[E0277]: `T` doesn't implement `std::fmt::Display` + --> $DIR/wf-bounds.rs:26:26 + | +LL | fn nya4<T>() -> impl Wf<NeedsDisplay<T>>; + | ^^^^^^^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter + | + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `NeedsDisplay` + --> $DIR/wf-bounds.rs:14:24 + | +LL | struct NeedsDisplay<T: Display>(T); + | ^^^^^^^ required by this bound in `NeedsDisplay` +help: consider restricting type parameter `T` + | +LL | fn nya4<T: std::fmt::Display>() -> impl Wf<NeedsDisplay<T>>; + | +++++++++++++++++++ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/in-trait/wf-bounds.next.stderr b/tests/ui/impl-trait/in-trait/wf-bounds.next.stderr index 1a70716123c..74c84c012b1 100644 --- a/tests/ui/impl-trait/in-trait/wf-bounds.next.stderr +++ b/tests/ui/impl-trait/in-trait/wf-bounds.next.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/wf-bounds.rs:13:22 + --> $DIR/wf-bounds.rs:17:22 | LL | fn nya() -> impl Wf<Vec<[u8]>>; | ^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -9,14 +9,14 @@ note: required by a bound in `Vec` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/wf-bounds.rs:16:23 + --> $DIR/wf-bounds.rs:20:23 | LL | fn nya2() -> impl Wf<[u8]>; | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `Wf` - --> $DIR/wf-bounds.rs:8:10 + --> $DIR/wf-bounds.rs:10:10 | LL | trait Wf<T> { | ^ required by this bound in `Wf` @@ -26,7 +26,7 @@ LL | trait Wf<T: ?Sized> { | ++++++++ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/wf-bounds.rs:19:44 + --> $DIR/wf-bounds.rs:23:44 | LL | fn nya3() -> impl Wf<(), Output = impl Wf<Vec<[u8]>>>; | ^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -35,6 +35,23 @@ LL | fn nya3() -> impl Wf<(), Output = impl Wf<Vec<[u8]>>>; note: required by a bound in `Vec` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -error: aborting due to 3 previous errors +error[E0277]: `T` doesn't implement `std::fmt::Display` + --> $DIR/wf-bounds.rs:26:26 + | +LL | fn nya4<T>() -> impl Wf<NeedsDisplay<T>>; + | ^^^^^^^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter + | + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `NeedsDisplay` + --> $DIR/wf-bounds.rs:14:24 + | +LL | struct NeedsDisplay<T: Display>(T); + | ^^^^^^^ required by this bound in `NeedsDisplay` +help: consider restricting type parameter `T` + | +LL | fn nya4<T: std::fmt::Display>() -> impl Wf<NeedsDisplay<T>>; + | +++++++++++++++++++ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/in-trait/wf-bounds.rs b/tests/ui/impl-trait/in-trait/wf-bounds.rs index 1c9590bd853..f8c1e561d5c 100644 --- a/tests/ui/impl-trait/in-trait/wf-bounds.rs +++ b/tests/ui/impl-trait/in-trait/wf-bounds.rs @@ -5,10 +5,14 @@ #![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] +use std::fmt::Display; + trait Wf<T> { type Output; } +struct NeedsDisplay<T: Display>(T); + trait Uwu { fn nya() -> impl Wf<Vec<[u8]>>; //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time @@ -18,6 +22,9 @@ trait Uwu { fn nya3() -> impl Wf<(), Output = impl Wf<Vec<[u8]>>>; //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time + + fn nya4<T>() -> impl Wf<NeedsDisplay<T>>; + //~^ ERROR `T` doesn't implement `std::fmt::Display` } fn main() {} diff --git a/tests/ui/impl-trait/issue-103181-2.rs b/tests/ui/impl-trait/issue-103181-2.rs index b43ac45075e..34deb98beef 100644 --- a/tests/ui/impl-trait/issue-103181-2.rs +++ b/tests/ui/impl-trait/issue-103181-2.rs @@ -24,6 +24,8 @@ where B: Send, // <- a second bound { normalize(broken_fut(), ()); + //~^ ERROR: cannot check whether the hidden type of opaque type satisfies auto traits + //~| ERROR: cannot check whether the hidden type of opaque type satisfies auto traits } fn main() {} diff --git a/tests/ui/impl-trait/issue-103181-2.stderr b/tests/ui/impl-trait/issue-103181-2.stderr index 5eb2dd9184b..cb5253ea6cd 100644 --- a/tests/ui/impl-trait/issue-103181-2.stderr +++ b/tests/ui/impl-trait/issue-103181-2.stderr @@ -4,6 +4,61 @@ error[E0425]: cannot find value `ident_error` in this scope LL | ident_error; | ^^^^^^^^^^^ not found in this scope -error: aborting due to previous error +error: cannot check whether the hidden type of opaque type satisfies auto traits + --> $DIR/issue-103181-2.rs:26:15 + | +LL | normalize(broken_fut(), ()); + | --------- ^^^^^^^^^^^^ + | | + | required by a bound introduced by this call + | +note: opaque type is declared here + --> $DIR/issue-103181-2.rs:11:23 + | +LL | async fn broken_fut() { + | ^ +note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule + --> $DIR/issue-103181-2.rs:20:10 + | +LL | async fn iceice<A, B>() + | ^^^^^^ +note: required for `impl Future<Output = ()>` to implement `SendFuture` + --> $DIR/issue-103181-2.rs:7:17 + | +LL | impl<Fut: Send> SendFuture for Fut { + | ---- ^^^^^^^^^^ ^^^ + | | + | unsatisfied trait bound introduced here +note: required by a bound in `normalize` + --> $DIR/issue-103181-2.rs:18:19 + | +LL | fn normalize<Fut: SendFuture>(_: Fut, _: Fut::Output) {} + | ^^^^^^^^^^ required by this bound in `normalize` + +error: cannot check whether the hidden type of opaque type satisfies auto traits + --> $DIR/issue-103181-2.rs:26:5 + | +LL | normalize(broken_fut(), ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: opaque type is declared here + --> $DIR/issue-103181-2.rs:11:23 + | +LL | async fn broken_fut() { + | ^ +note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule + --> $DIR/issue-103181-2.rs:20:10 + | +LL | async fn iceice<A, B>() + | ^^^^^^ +note: required for `impl Future<Output = ()>` to implement `SendFuture` + --> $DIR/issue-103181-2.rs:7:17 + | +LL | impl<Fut: Send> SendFuture for Fut { + | ---- ^^^^^^^^^^ ^^^ + | | + | unsatisfied trait bound introduced here + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/impl-trait/issue-55872-3.rs b/tests/ui/impl-trait/issue-55872-3.rs index d031271ac08..7490a130800 100644 --- a/tests/ui/impl-trait/issue-55872-3.rs +++ b/tests/ui/impl-trait/issue-55872-3.rs @@ -1,5 +1,4 @@ // edition:2018 -// ignore-compare-mode-chalk #![feature(impl_trait_in_assoc_type)] diff --git a/tests/ui/impl-trait/issue-55872-3.stderr b/tests/ui/impl-trait/issue-55872-3.stderr index c6e10f0f350..82798897433 100644 --- a/tests/ui/impl-trait/issue-55872-3.stderr +++ b/tests/ui/impl-trait/issue-55872-3.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `[async block@$DIR/issue-55872-3.rs:16:9: 16:17]: Copy` is not satisfied - --> $DIR/issue-55872-3.rs:14:20 +error[E0277]: the trait bound `[async block@$DIR/issue-55872-3.rs:15:9: 15:17]: Copy` is not satisfied + --> $DIR/issue-55872-3.rs:13:20 | LL | fn foo<T>() -> Self::E { - | ^^^^^^^ the trait `Copy` is not implemented for `[async block@$DIR/issue-55872-3.rs:16:9: 16:17]` + | ^^^^^^^ the trait `Copy` is not implemented for `[async block@$DIR/issue-55872-3.rs:15:9: 15:17]` error: aborting due to previous error diff --git a/tests/ui/impl-trait/issues/issue-65581.rs b/tests/ui/impl-trait/issues/issue-65581.rs index b947fc1d239..af65b79d3e8 100644 --- a/tests/ui/impl-trait/issues/issue-65581.rs +++ b/tests/ui/impl-trait/issues/issue-65581.rs @@ -1,5 +1,4 @@ // check-pass -// ignore-compare-mode-chalk #![allow(dead_code)] diff --git a/tests/ui/issues/issue-35570.rs b/tests/ui/issues/issue-35570.rs index a2b0222d4f3..42bdb423f8f 100644 --- a/tests/ui/issues/issue-35570.rs +++ b/tests/ui/issues/issue-35570.rs @@ -7,7 +7,6 @@ trait Trait2<'a> { fn _ice(param: Box<dyn for <'a> Trait1<<() as Trait2<'a>>::Ty>>) { //~^ ERROR the trait bound `for<'a> (): Trait2<'a>` is not satisfied - //~| ERROR the trait bound `for<'a> (): Trait2<'a>` is not satisfied let _e: (usize, usize) = unsafe{mem::transmute(param)}; } diff --git a/tests/ui/issues/issue-35570.stderr b/tests/ui/issues/issue-35570.stderr index 3dc33729d8f..2697d46bdb2 100644 --- a/tests/ui/issues/issue-35570.stderr +++ b/tests/ui/issues/issue-35570.stderr @@ -4,16 +4,6 @@ error[E0277]: the trait bound `for<'a> (): Trait2<'a>` is not satisfied LL | fn _ice(param: Box<dyn for <'a> Trait1<<() as Trait2<'a>>::Ty>>) { | ^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Trait2<'a>` is not implemented for `()` -error[E0277]: the trait bound `for<'a> (): Trait2<'a>` is not satisfied - --> $DIR/issue-35570.rs:8:1 - | -LL | / fn _ice(param: Box<dyn for <'a> Trait1<<() as Trait2<'a>>::Ty>>) { -LL | | -LL | | -LL | | let _e: (usize, usize) = unsafe{mem::transmute(param)}; -LL | | } - | |_^ the trait `for<'a> Trait2<'a>` is not implemented for `()` - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/limits/huge-array-simple-32.rs b/tests/ui/limits/huge-array-simple-32.rs index 2290e3d5e76..f25b8887402 100644 --- a/tests/ui/limits/huge-array-simple-32.rs +++ b/tests/ui/limits/huge-array-simple-32.rs @@ -1,9 +1,6 @@ // ignore-64bit // build-fail -// FIXME https://github.com/rust-lang/rust/issues/59774 -// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" -// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" #![allow(arithmetic_overflow)] fn main() { diff --git a/tests/ui/limits/huge-array-simple-32.stderr b/tests/ui/limits/huge-array-simple-32.stderr index 31e120df626..d1e4e6295a9 100644 --- a/tests/ui/limits/huge-array-simple-32.stderr +++ b/tests/ui/limits/huge-array-simple-32.stderr @@ -1,5 +1,5 @@ error: values of the type `[u8; 2147516416]` are too big for the current architecture - --> $DIR/huge-array-simple-32.rs:10:9 + --> $DIR/huge-array-simple-32.rs:7:9 | LL | let _fat: [u8; (1<<31)+(1<<15)] = | ^^^^ diff --git a/tests/ui/limits/huge-array-simple-64.rs b/tests/ui/limits/huge-array-simple-64.rs index 02c961fc5fa..c5778c428ae 100644 --- a/tests/ui/limits/huge-array-simple-64.rs +++ b/tests/ui/limits/huge-array-simple-64.rs @@ -1,9 +1,6 @@ // build-fail // ignore-32bit -// FIXME https://github.com/rust-lang/rust/issues/59774 -// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" -// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" #![allow(arithmetic_overflow)] fn main() { diff --git a/tests/ui/limits/huge-array-simple-64.stderr b/tests/ui/limits/huge-array-simple-64.stderr index c5d3fe85d0d..5791b6439c9 100644 --- a/tests/ui/limits/huge-array-simple-64.stderr +++ b/tests/ui/limits/huge-array-simple-64.stderr @@ -1,5 +1,5 @@ error: values of the type `[u8; 2305843011361177600]` are too big for the current architecture - --> $DIR/huge-array-simple-64.rs:10:9 + --> $DIR/huge-array-simple-64.rs:7:9 | LL | let _fat: [u8; (1<<61)+(1<<31)] = | ^^^^ diff --git a/tests/ui/limits/huge-array.rs b/tests/ui/limits/huge-array.rs index 3070801f865..811cf25dd76 100644 --- a/tests/ui/limits/huge-array.rs +++ b/tests/ui/limits/huge-array.rs @@ -1,8 +1,4 @@ -// FIXME https://github.com/rust-lang/rust/issues/59774 - // build-fail -// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" -// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" fn generic<T: Copy>(t: T) { let s: [T; 1518600000] = [t; 1518600000]; diff --git a/tests/ui/limits/huge-array.stderr b/tests/ui/limits/huge-array.stderr index 817458b73e4..24adb33b088 100644 --- a/tests/ui/limits/huge-array.stderr +++ b/tests/ui/limits/huge-array.stderr @@ -1,5 +1,5 @@ error: values of the type `[[u8; 1518599999]; 1518600000]` are too big for the current architecture - --> $DIR/huge-array.rs:8:9 + --> $DIR/huge-array.rs:4:9 | LL | let s: [T; 1518600000] = [t; 1518600000]; | ^ diff --git a/tests/ui/limits/huge-enum.rs b/tests/ui/limits/huge-enum.rs index 39ea6e11b1f..dd4bae60d3e 100644 --- a/tests/ui/limits/huge-enum.rs +++ b/tests/ui/limits/huge-enum.rs @@ -2,10 +2,6 @@ // normalize-stderr-test "std::option::Option<\[u32; \d+\]>" -> "TYPE" // normalize-stderr-test "\[u32; \d+\]" -> "TYPE" -// FIXME https://github.com/rust-lang/rust/issues/59774 -// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" -// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" - #[cfg(target_pointer_width = "32")] type BIG = Option<[u32; (1<<29)-1]>; diff --git a/tests/ui/limits/huge-enum.stderr b/tests/ui/limits/huge-enum.stderr index a1456e1a8ab..5e2bda9be50 100644 --- a/tests/ui/limits/huge-enum.stderr +++ b/tests/ui/limits/huge-enum.stderr @@ -1,5 +1,5 @@ error: values of the type `Option<TYPE>` are too big for the current architecture - --> $DIR/huge-enum.rs:16:9 + --> $DIR/huge-enum.rs:12:9 | LL | let big: BIG = None; | ^^^ diff --git a/tests/ui/limits/huge-struct.rs b/tests/ui/limits/huge-struct.rs index 02f38d860b4..904e2774b19 100644 --- a/tests/ui/limits/huge-struct.rs +++ b/tests/ui/limits/huge-struct.rs @@ -3,10 +3,6 @@ // normalize-stderr-test "S1M" -> "SXX" // error-pattern: too big for the current -// FIXME https://github.com/rust-lang/rust/issues/59774 -// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" -// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" - struct S32<T> { v0: T, v1: T, diff --git a/tests/ui/limits/huge-struct.stderr b/tests/ui/limits/huge-struct.stderr index f0ee88e5955..ce14bc5b888 100644 --- a/tests/ui/limits/huge-struct.stderr +++ b/tests/ui/limits/huge-struct.stderr @@ -1,5 +1,5 @@ error: values of the type `SXX<SXX<SXX<u32>>>` are too big for the current architecture - --> $DIR/huge-struct.rs:50:9 + --> $DIR/huge-struct.rs:46:9 | LL | let fat: Option<SXX<SXX<SXX<u32>>>> = None; | ^^^ diff --git a/tests/ui/limits/issue-15919-32.rs b/tests/ui/limits/issue-15919-32.rs index 3c93f14ccc7..3254cb2c5bb 100644 --- a/tests/ui/limits/issue-15919-32.rs +++ b/tests/ui/limits/issue-15919-32.rs @@ -1,10 +1,6 @@ // ignore-64bit // build-fail -// FIXME https://github.com/rust-lang/rust/issues/59774 -// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" -// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" - fn main() { let x = [0usize; 0xffff_ffff]; //~ ERROR too big } diff --git a/tests/ui/limits/issue-15919-32.stderr b/tests/ui/limits/issue-15919-32.stderr index 0d79fc0c770..f9e48a52cb9 100644 --- a/tests/ui/limits/issue-15919-32.stderr +++ b/tests/ui/limits/issue-15919-32.stderr @@ -1,5 +1,5 @@ error: values of the type `[usize; usize::MAX]` are too big for the current architecture - --> $DIR/issue-15919-32.rs:9:9 + --> $DIR/issue-15919-32.rs:5:9 | LL | let x = [0usize; 0xffff_ffff]; | ^ diff --git a/tests/ui/limits/issue-15919-64.rs b/tests/ui/limits/issue-15919-64.rs index 3ecbd34eaaa..272e8800d68 100644 --- a/tests/ui/limits/issue-15919-64.rs +++ b/tests/ui/limits/issue-15919-64.rs @@ -1,10 +1,6 @@ // build-fail // ignore-32bit -// FIXME https://github.com/rust-lang/rust/issues/59774 -// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" -// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" - fn main() { let x = [0usize; 0xffff_ffff_ffff_ffff]; //~ ERROR too big } diff --git a/tests/ui/limits/issue-15919-64.stderr b/tests/ui/limits/issue-15919-64.stderr index 3399d644ede..167272890aa 100644 --- a/tests/ui/limits/issue-15919-64.stderr +++ b/tests/ui/limits/issue-15919-64.stderr @@ -1,5 +1,5 @@ error: values of the type `[usize; usize::MAX]` are too big for the current architecture - --> $DIR/issue-15919-64.rs:9:9 + --> $DIR/issue-15919-64.rs:5:9 | LL | let x = [0usize; 0xffff_ffff_ffff_ffff]; | ^ diff --git a/tests/ui/limits/issue-17913.rs b/tests/ui/limits/issue-17913.rs index 56cf5d831bd..6b37d6f0551 100644 --- a/tests/ui/limits/issue-17913.rs +++ b/tests/ui/limits/issue-17913.rs @@ -2,10 +2,6 @@ // normalize-stderr-test "\[&usize; \d+\]" -> "[&usize; usize::MAX]" // error-pattern: too big for the current architecture -// FIXME https://github.com/rust-lang/rust/issues/59774 -// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" -// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" - #[cfg(target_pointer_width = "64")] fn main() { let n = 0_usize; diff --git a/tests/ui/limits/issue-56762.rs b/tests/ui/limits/issue-56762.rs index fb0a270f18b..ed7ee4da85d 100644 --- a/tests/ui/limits/issue-56762.rs +++ b/tests/ui/limits/issue-56762.rs @@ -1,8 +1,5 @@ // only-x86_64 -// FIXME https://github.com/rust-lang/rust/issues/59774 -// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" -// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" const HUGE_SIZE: usize = !0usize / 8; diff --git a/tests/ui/limits/issue-56762.stderr b/tests/ui/limits/issue-56762.stderr index e6b9c676278..29f2a8859ee 100644 --- a/tests/ui/limits/issue-56762.stderr +++ b/tests/ui/limits/issue-56762.stderr @@ -1,11 +1,11 @@ error[E0080]: values of the type `[u8; 2305843009213693951]` are too big for the current architecture - --> $DIR/issue-56762.rs:19:1 + --> $DIR/issue-56762.rs:16:1 | LL | static MY_TOO_BIG_ARRAY_1: TooBigArray = TooBigArray::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: values of the type `[u8; 2305843009213693951]` are too big for the current architecture - --> $DIR/issue-56762.rs:21:1 + --> $DIR/issue-56762.rs:18:1 | LL | static MY_TOO_BIG_ARRAY_2: [u8; HUGE_SIZE] = [0x00; HUGE_SIZE]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/linkage-attr/linkage3.rs b/tests/ui/linkage-attr/linkage3.rs index 112eb1d3bd9..cac10af6338 100644 --- a/tests/ui/linkage-attr/linkage3.rs +++ b/tests/ui/linkage-attr/linkage3.rs @@ -1,8 +1,4 @@ -// FIXME https://github.com/rust-lang/rust/issues/59774 - // check-fail -// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" -// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" #![feature(linkage)] diff --git a/tests/ui/linkage-attr/linkage3.stderr b/tests/ui/linkage-attr/linkage3.stderr index f2579c6e850..dbb5880ab92 100644 --- a/tests/ui/linkage-attr/linkage3.stderr +++ b/tests/ui/linkage-attr/linkage3.stderr @@ -1,5 +1,5 @@ error: invalid linkage specified - --> $DIR/linkage3.rs:11:5 + --> $DIR/linkage3.rs:7:5 | LL | static foo: *const i32; | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/lint-ctypes-94223.rs b/tests/ui/lint/lint-ctypes-94223.rs new file mode 100644 index 00000000000..70dd2a71f26 --- /dev/null +++ b/tests/ui/lint/lint-ctypes-94223.rs @@ -0,0 +1,42 @@ +#![crate_type = "lib"] +#![deny(improper_ctypes_definitions)] + +pub fn bad(f: extern "C" fn([u8])) {} +//~^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe + +pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {} +//~^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe +//~^^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe + +struct BadStruct(extern "C" fn([u8])); +//~^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe + +enum BadEnum { + A(extern "C" fn([u8])), + //~^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe +} + +enum BadUnion { + A(extern "C" fn([u8])), + //~^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe +} + +type Foo = extern "C" fn([u8]); +//~^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe + +pub struct FfiUnsafe; + +#[allow(improper_ctypes_definitions)] +extern "C" fn f(_: FfiUnsafe) { + unimplemented!() +} + +pub static BAD: extern "C" fn(FfiUnsafe) = f; +//~^ ERROR `extern` fn uses type `FfiUnsafe`, which is not FFI-safe + +pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUnsafe)> = Ok(f); +//~^ ERROR `extern` fn uses type `FfiUnsafe`, which is not FFI-safe +//~^^ ERROR `extern` fn uses type `FfiUnsafe`, which is not FFI-safe + +pub const BAD_CONST: extern "C" fn(FfiUnsafe) = f; +//~^ ERROR `extern` fn uses type `FfiUnsafe`, which is not FFI-safe diff --git a/tests/ui/lint/lint-ctypes-94223.stderr b/tests/ui/lint/lint-ctypes-94223.stderr new file mode 100644 index 00000000000..49e64ed5140 --- /dev/null +++ b/tests/ui/lint/lint-ctypes-94223.stderr @@ -0,0 +1,126 @@ +error: `extern` fn uses type `[u8]`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:4:15 + | +LL | pub fn bad(f: extern "C" fn([u8])) {} + | ^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider using a raw pointer instead + = note: slices have no C equivalent +note: the lint level is defined here + --> $DIR/lint-ctypes-94223.rs:2:9 + | +LL | #![deny(improper_ctypes_definitions)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `extern` fn uses type `[u8]`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:7:28 + | +LL | pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {} + | ^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider using a raw pointer instead + = note: slices have no C equivalent + +error: `extern` fn uses type `[u8]`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:7:49 + | +LL | pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {} + | ^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider using a raw pointer instead + = note: slices have no C equivalent + +error: `extern` fn uses type `[u8]`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:11:18 + | +LL | struct BadStruct(extern "C" fn([u8])); + | ^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider using a raw pointer instead + = note: slices have no C equivalent + +error: `extern` fn uses type `[u8]`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:15:7 + | +LL | A(extern "C" fn([u8])), + | ^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider using a raw pointer instead + = note: slices have no C equivalent + +error: `extern` fn uses type `[u8]`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:20:7 + | +LL | A(extern "C" fn([u8])), + | ^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider using a raw pointer instead + = note: slices have no C equivalent + +error: `extern` fn uses type `[u8]`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:24:12 + | +LL | type Foo = extern "C" fn([u8]); + | ^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider using a raw pointer instead + = note: slices have no C equivalent + +error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:34:17 + | +LL | pub static BAD: extern "C" fn(FfiUnsafe) = f; + | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout +note: the type is defined here + --> $DIR/lint-ctypes-94223.rs:27:1 + | +LL | pub struct FfiUnsafe; + | ^^^^^^^^^^^^^^^^^^^^ + +error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:37:30 + | +LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUnsafe)> = Ok(f); + | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout +note: the type is defined here + --> $DIR/lint-ctypes-94223.rs:27:1 + | +LL | pub struct FfiUnsafe; + | ^^^^^^^^^^^^^^^^^^^^ + +error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:37:56 + | +LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUnsafe)> = Ok(f); + | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout +note: the type is defined here + --> $DIR/lint-ctypes-94223.rs:27:1 + | +LL | pub struct FfiUnsafe; + | ^^^^^^^^^^^^^^^^^^^^ + +error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:41:22 + | +LL | pub const BAD_CONST: extern "C" fn(FfiUnsafe) = f; + | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout +note: the type is defined here + --> $DIR/lint-ctypes-94223.rs:27:1 + | +LL | pub struct FfiUnsafe; + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 11 previous errors + diff --git a/tests/ui/macros/builtin-prelude-no-accidents.stderr b/tests/ui/macros/builtin-prelude-no-accidents.stderr index 8cd9a63b808..b726e186241 100644 --- a/tests/ui/macros/builtin-prelude-no-accidents.stderr +++ b/tests/ui/macros/builtin-prelude-no-accidents.stderr @@ -3,21 +3,37 @@ error[E0433]: failed to resolve: use of undeclared crate or module `env` | LL | env::current_dir; | ^^^ use of undeclared crate or module `env` - -error[E0433]: failed to resolve: use of undeclared crate or module `vec` - --> $DIR/builtin-prelude-no-accidents.rs:7:14 | -LL | type B = vec::Vec<u8>; - | ^^^ - | | - | use of undeclared crate or module `vec` - | help: a struct with a similar name exists (notice the capitalization): `Vec` +help: consider importing this module + | +LL + use std::env; + | error[E0433]: failed to resolve: use of undeclared crate or module `panic` --> $DIR/builtin-prelude-no-accidents.rs:6:14 | LL | type A = panic::PanicInfo; | ^^^^^ use of undeclared crate or module `panic` + | +help: consider importing this module + | +LL + use std::panic; + | + +error[E0433]: failed to resolve: use of undeclared crate or module `vec` + --> $DIR/builtin-prelude-no-accidents.rs:7:14 + | +LL | type B = vec::Vec<u8>; + | ^^^ use of undeclared crate or module `vec` + | +help: a struct with a similar name exists + | +LL | type B = Vec::Vec<u8>; + | ~~~ +help: consider importing this module + | +LL + use std::vec; + | error: aborting due to 3 previous errors diff --git a/tests/ui/object-safety/assoc_type_bounds_sized.rs b/tests/ui/object-safety/assoc_type_bounds_sized.rs index 61ad3cf9dc6..6d10ceeb1b4 100644 --- a/tests/ui/object-safety/assoc_type_bounds_sized.rs +++ b/tests/ui/object-safety/assoc_type_bounds_sized.rs @@ -1,9 +1,24 @@ +//! This test checks that associated types only need to be +//! mentioned in trait objects, if they don't require `Self: Sized`. + +// check-pass + trait Foo { type Bar where Self: Sized; } -fn foo(_: &dyn Foo) {} //~ ERROR: the value of the associated type `Bar` (from trait `Foo`) must be specified +fn foo(_: &dyn Foo) {} + +trait Other: Sized {} + +trait Boo { + type Assoc + where + Self: Other; +} + +fn boo(_: &dyn Boo) {} fn main() {} diff --git a/tests/ui/object-safety/assoc_type_bounds_sized.stderr b/tests/ui/object-safety/assoc_type_bounds_sized.stderr deleted file mode 100644 index 49d624f9b1d..00000000000 --- a/tests/ui/object-safety/assoc_type_bounds_sized.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0191]: the value of the associated type `Bar` (from trait `Foo`) must be specified - --> $DIR/assoc_type_bounds_sized.rs:7:16 - | -LL | type Bar - | -------- `Bar` defined here -... -LL | fn foo(_: &dyn Foo) {} - | ^^^ help: specify the associated type: `Foo<Bar = Type>` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0191`. diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_others.rs b/tests/ui/object-safety/assoc_type_bounds_sized_others.rs new file mode 100644 index 00000000000..647b72a759f --- /dev/null +++ b/tests/ui/object-safety/assoc_type_bounds_sized_others.rs @@ -0,0 +1,25 @@ +//! This test checks that even if some associated types have +//! `where Self: Sized` bounds, those without still need to be +//! mentioned in trait objects. + +trait Foo { + type Bar + where + Self: Sized; + type Bop; +} + +fn foo(_: &dyn Foo) {} +//~^ ERROR the value of the associated type `Bop` (from trait `Foo`) must be specified + +trait Bar { + type Bop; + type Bar + where + Self: Sized; +} + +fn bar(_: &dyn Bar) {} +//~^ ERROR the value of the associated type `Bop` (from trait `Bar`) must be specified + +fn main() {} diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_others.stderr b/tests/ui/object-safety/assoc_type_bounds_sized_others.stderr new file mode 100644 index 00000000000..e4c44334b34 --- /dev/null +++ b/tests/ui/object-safety/assoc_type_bounds_sized_others.stderr @@ -0,0 +1,21 @@ +error[E0191]: the value of the associated type `Bop` (from trait `Foo`) must be specified + --> $DIR/assoc_type_bounds_sized_others.rs:12:16 + | +LL | type Bop; + | -------- `Bop` defined here +... +LL | fn foo(_: &dyn Foo) {} + | ^^^ help: specify the associated type: `Foo<Bop = Type>` + +error[E0191]: the value of the associated type `Bop` (from trait `Bar`) must be specified + --> $DIR/assoc_type_bounds_sized_others.rs:22:16 + | +LL | type Bop; + | -------- `Bop` defined here +... +LL | fn bar(_: &dyn Bar) {} + | ^^^ help: specify the associated type: `Bar<Bop = Type>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0191`. diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.rs b/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.rs new file mode 100644 index 00000000000..800624e3124 --- /dev/null +++ b/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.rs @@ -0,0 +1,17 @@ +// check-pass + +trait Foo { + type Bar + where + Self: Sized; +} + +fn foo(_: &dyn Foo<Bar = ()>) {} +//~^ WARN: unnecessary associated type bound for not object safe associated type +//~| WARN: unnecessary associated type bound for not object safe associated type +//~| WARN: unnecessary associated type bound for not object safe associated type + +#[allow(unused_associated_type_bounds)] +fn bar(_: &dyn Foo<Bar = ()>) {} + +fn main() {} diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.stderr b/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.stderr new file mode 100644 index 00000000000..d0a4179fe3e --- /dev/null +++ b/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.stderr @@ -0,0 +1,27 @@ +warning: unnecessary associated type bound for not object safe associated type + --> $DIR/assoc_type_bounds_sized_unnecessary.rs:9:20 + | +LL | fn foo(_: &dyn Foo<Bar = ()>) {} + | ^^^^^^^^ help: remove this bound + | + = note: this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`. + = note: `#[warn(unused_associated_type_bounds)]` on by default + +warning: unnecessary associated type bound for not object safe associated type + --> $DIR/assoc_type_bounds_sized_unnecessary.rs:9:20 + | +LL | fn foo(_: &dyn Foo<Bar = ()>) {} + | ^^^^^^^^ help: remove this bound + | + = note: this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`. + +warning: unnecessary associated type bound for not object safe associated type + --> $DIR/assoc_type_bounds_sized_unnecessary.rs:9:20 + | +LL | fn foo(_: &dyn Foo<Bar = ()>) {} + | ^^^^^^^^ help: remove this bound + | + = note: this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`. + +warning: 3 warnings emitted + diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_used.rs b/tests/ui/object-safety/assoc_type_bounds_sized_used.rs new file mode 100644 index 00000000000..cf5345b1c1d --- /dev/null +++ b/tests/ui/object-safety/assoc_type_bounds_sized_used.rs @@ -0,0 +1,20 @@ +//! This test checks that even if some associated types have +//! `where Self: Sized` bounds, those without still need to be +//! mentioned in trait objects. + +trait Bop { + type Bar: Default + where + Self: Sized; +} + +fn bop<T: Bop + ?Sized>() { + let _ = <T as Bop>::Bar::default(); + //~^ ERROR: trait bounds were not satisfied + //~| ERROR: the size for values of type `T` cannot be known at compilation time +} + +fn main() { + bop::<dyn Bop>(); + //~^ ERROR: the size for values of type `dyn Bop` cannot be known at compilation time +} diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr b/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr new file mode 100644 index 00000000000..f8488d842e2 --- /dev/null +++ b/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr @@ -0,0 +1,53 @@ +error[E0599]: the function or associated item `default` exists for associated type `<T as Bop>::Bar`, but its trait bounds were not satisfied + --> $DIR/assoc_type_bounds_sized_used.rs:12:30 + | +LL | let _ = <T as Bop>::Bar::default(); + | ^^^^^^^ function or associated item cannot be called on `<T as Bop>::Bar` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `T: Sized` + which is required by `<T as Bop>::Bar: Default` +help: consider restricting the type parameter to satisfy the trait bound + | +LL | fn bop<T: Bop + ?Sized>() where T: Sized { + | ++++++++++++++ + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/assoc_type_bounds_sized_used.rs:12:13 + | +LL | fn bop<T: Bop + ?Sized>() { + | - this type parameter needs to be `Sized` +LL | let _ = <T as Bop>::Bar::default(); + | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | +note: required by a bound in `Bop::Bar` + --> $DIR/assoc_type_bounds_sized_used.rs:8:15 + | +LL | type Bar: Default + | --- required by a bound in this associated type +LL | where +LL | Self: Sized; + | ^^^^^ required by this bound in `Bop::Bar` +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - fn bop<T: Bop + ?Sized>() { +LL + fn bop<T: Bop>() { + | + +error[E0277]: the size for values of type `dyn Bop` cannot be known at compilation time + --> $DIR/assoc_type_bounds_sized_used.rs:18:11 + | +LL | bop::<dyn Bop>(); + | ^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `dyn Bop` +note: required by a bound in `bop` + --> $DIR/assoc_type_bounds_sized_used.rs:11:11 + | +LL | fn bop<T: Bop + ?Sized>() { + | ^^^ required by this bound in `bop` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0599. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/parser/issue-113342.rs b/tests/ui/parser/issue-113342.rs new file mode 100644 index 00000000000..18b502736f7 --- /dev/null +++ b/tests/ui/parser/issue-113342.rs @@ -0,0 +1,9 @@ +#[link(name = "my_c_library")] +extern "C" { + fn my_c_function(x: i32) -> bool; +} + +#[no_mangle] +extern "C" pub fn id(x: i32) -> i32 { x } //~ ERROR expected `fn`, found keyword `pub` + +fn main() {} diff --git a/tests/ui/parser/issue-113342.stderr b/tests/ui/parser/issue-113342.stderr new file mode 100644 index 00000000000..a0c5e665ff8 --- /dev/null +++ b/tests/ui/parser/issue-113342.stderr @@ -0,0 +1,11 @@ +error: expected `fn`, found keyword `pub` + --> $DIR/issue-113342.rs:7:12 + | +LL | extern "C" pub fn id(x: i32) -> i32 { x } + | -----------^^^ + | | | + | | expected `fn` + | help: visibility `pub` must come before `extern "C"`: `pub extern "C"` + +error: aborting due to previous error + diff --git a/tests/ui/parser/utf16-be-without-bom.stderr b/tests/ui/parser/utf16-be-without-bom.stderr index 768d2c53164..c041f3ecf53 100644 --- a/tests/ui/parser/utf16-be-without-bom.stderr +++ b/tests/ui/parser/utf16-be-without-bom.stderr Binary files differdiff --git a/tests/ui/parser/utf16-le-without-bom.stderr b/tests/ui/parser/utf16-le-without-bom.stderr index 4f4b91e39ed..cc2220441ac 100644 --- a/tests/ui/parser/utf16-le-without-bom.stderr +++ b/tests/ui/parser/utf16-le-without-bom.stderr Binary files differdiff --git a/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.rs b/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.rs index 1106352037a..429548f119b 100644 --- a/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.rs +++ b/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.rs @@ -20,7 +20,6 @@ trait Trait2<'a, 'b> { // do not infer that. fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >) //~^ ERROR the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied - //~| ERROR the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied { } diff --git a/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr b/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr index 3fd39810d44..6844e866532 100644 --- a/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr +++ b/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr @@ -9,21 +9,6 @@ help: consider restricting type parameter `T` LL | fn callee<'x, 'y, T: for<'z> Trait2<'y, 'z>>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >) | ++++++++++++++++++++++++ -error[E0277]: the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied - --> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:21:1 - | -LL | / fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >) -LL | | -LL | | -LL | | { -LL | | } - | |_^ the trait `for<'z> Trait2<'y, 'z>` is not implemented for `T` - | -help: consider restricting type parameter `T` - | -LL | fn callee<'x, 'y, T: for<'z> Trait2<'y, 'z>>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >) - | ++++++++++++++++++++++++ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/resolve/export-fully-qualified-2018.rs b/tests/ui/resolve/export-fully-qualified-2018.rs new file mode 100644 index 00000000000..afd48acb6bb --- /dev/null +++ b/tests/ui/resolve/export-fully-qualified-2018.rs @@ -0,0 +1,13 @@ +// edition:2018 + +// In this test baz isn't resolved when called as foo.baz even though +// it's called from inside foo. This is somewhat surprising and may +// want to change eventually. + +mod foo { + pub fn bar() { foo::baz(); } //~ ERROR failed to resolve: use of undeclared crate or module `foo` + + fn baz() { } +} + +fn main() { } diff --git a/tests/ui/resolve/export-fully-qualified-2018.stderr b/tests/ui/resolve/export-fully-qualified-2018.stderr new file mode 100644 index 00000000000..366ffd9bb2b --- /dev/null +++ b/tests/ui/resolve/export-fully-qualified-2018.stderr @@ -0,0 +1,14 @@ +error[E0433]: failed to resolve: use of undeclared crate or module `foo` + --> $DIR/export-fully-qualified-2018.rs:8:20 + | +LL | pub fn bar() { foo::baz(); } + | ^^^ use of undeclared crate or module `foo` + | +help: consider importing this module + | +LL + use crate::foo; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/resolve/export-fully-qualified.rs b/tests/ui/resolve/export-fully-qualified.rs index 4e73a2c5488..9d4daf4cd79 100644 --- a/tests/ui/resolve/export-fully-qualified.rs +++ b/tests/ui/resolve/export-fully-qualified.rs @@ -1,3 +1,5 @@ +// edition:2015 + // In this test baz isn't resolved when called as foo.baz even though // it's called from inside foo. This is somewhat surprising and may // want to change eventually. diff --git a/tests/ui/resolve/export-fully-qualified.stderr b/tests/ui/resolve/export-fully-qualified.stderr index 7ee352e1232..0cd516ee1b1 100644 --- a/tests/ui/resolve/export-fully-qualified.stderr +++ b/tests/ui/resolve/export-fully-qualified.stderr @@ -1,8 +1,13 @@ error[E0433]: failed to resolve: use of undeclared crate or module `foo` - --> $DIR/export-fully-qualified.rs:6:20 + --> $DIR/export-fully-qualified.rs:8:20 | LL | pub fn bar() { foo::baz(); } | ^^^ use of undeclared crate or module `foo` + | +help: consider importing this module + | +LL + use foo; + | error: aborting due to previous error diff --git a/tests/ui/resolve/resolve-self-in-impl.stderr b/tests/ui/resolve/resolve-self-in-impl.stderr index b3042d41346..9f9ed68898f 100644 --- a/tests/ui/resolve/resolve-self-in-impl.stderr +++ b/tests/ui/resolve/resolve-self-in-impl.stderr @@ -1,40 +1,40 @@ error: `Self` is not valid in the self type of an impl block - --> $DIR/resolve-self-in-impl.rs:16:6 + --> $DIR/resolve-self-in-impl.rs:14:13 | -LL | impl Self {} - | ^^^^ +LL | impl Tr for Self {} + | ^^^^ | = note: replace `Self` with a different type error: `Self` is not valid in the self type of an impl block - --> $DIR/resolve-self-in-impl.rs:17:8 + --> $DIR/resolve-self-in-impl.rs:15:15 | -LL | impl S<Self> {} - | ^^^^ +LL | impl Tr for S<Self> {} + | ^^^^ | = note: replace `Self` with a different type error: `Self` is not valid in the self type of an impl block - --> $DIR/resolve-self-in-impl.rs:18:7 + --> $DIR/resolve-self-in-impl.rs:16:6 | -LL | impl (Self, Self) {} - | ^^^^ ^^^^ +LL | impl Self {} + | ^^^^ | = note: replace `Self` with a different type error: `Self` is not valid in the self type of an impl block - --> $DIR/resolve-self-in-impl.rs:14:13 + --> $DIR/resolve-self-in-impl.rs:17:8 | -LL | impl Tr for Self {} - | ^^^^ +LL | impl S<Self> {} + | ^^^^ | = note: replace `Self` with a different type error: `Self` is not valid in the self type of an impl block - --> $DIR/resolve-self-in-impl.rs:15:15 + --> $DIR/resolve-self-in-impl.rs:18:7 | -LL | impl Tr for S<Self> {} - | ^^^^ +LL | impl (Self, Self) {} + | ^^^^ ^^^^ | = note: replace `Self` with a different type diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs new file mode 100644 index 00000000000..49457354cc9 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs @@ -0,0 +1,29 @@ +// check-pass + +// gate-test-effects +// ^ effects doesn't have a gate so we will trick tidy into thinking this is a gate test + +#![feature(const_trait_impl, effects, rustc_attrs)] + +// ensure we are passing in the correct host effect in always const contexts. + +pub const fn hmm</* T, */ #[rustc_host] const host: bool = true>() -> usize { + if host { + 1 + } else { + 0 + } +} + +const _: () = { + let x = hmm(); + assert!(0 == x); +}; + +/* FIXME(effects) +pub const fn uwu(x: [u8; hmm::<()>()]) { + let [] = x; +} +*/ + +fn main() {} diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/basic.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/basic.rs index e4b07ab8108..3fc5fd481ea 100644 --- a/tests/ui/rfcs/rfc-3348-c-string-literals/basic.rs +++ b/tests/ui/rfcs/rfc-3348-c-string-literals/basic.rs @@ -1,4 +1,6 @@ -// run-pass +// FIXME(c_str_literals): This should be `run-pass` +// known-bug: #113333 +// edition: 2021 #![feature(c_str_literals)] diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/basic.stderr b/tests/ui/rfcs/rfc-3348-c-string-literals/basic.stderr new file mode 100644 index 00000000000..571c319d8c5 --- /dev/null +++ b/tests/ui/rfcs/rfc-3348-c-string-literals/basic.stderr @@ -0,0 +1,25 @@ +error: prefix `c` is unknown + --> $DIR/basic.rs:8:27 + | +LL | assert_eq!(b"test\0", c"test".to_bytes_with_nul()); + | ^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: consider inserting whitespace here + | +LL | assert_eq!(b"test\0", c "test".to_bytes_with_nul()); + | + + +error: no rules expected the token `"test"` + --> $DIR/basic.rs:8:28 + | +LL | assert_eq!(b"test\0", c"test".to_bytes_with_nul()); + | -^^^^^ + | | + | no rules expected this token in macro call + | help: missing comma here + | + = note: while trying to match sequence start + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/edition-2015-2018-lexing.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/edition-2015-2018-lexing.rs new file mode 100644 index 00000000000..2a4cd600426 --- /dev/null +++ b/tests/ui/rfcs/rfc-3348-c-string-literals/edition-2015-2018-lexing.rs @@ -0,0 +1,24 @@ +// Regression test for issue #113235. + +// check-pass +// revisions: edition2015 edition2018 +//[edition2015] edition: 2015 +//[edition2018] edition: 2018 + +// Make sure that in pre-2021 editions we continue to parse the snippet +// `c"hello"` as an identifier followed by a (normal) string literal and +// allow the code below to compile. +// Prefixes including `c` as used by C string literals are only reserved +// in edition 2021 and onward. +// +// Consider checking out rust-2021/reserved-prefixes-migration.rs as well. + +macro_rules! parse { + (c $e:expr) => { + $e + }; +} + +fn main() { + let _: &'static str = parse!(c"hello"); +} diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/gate.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/gate.rs index b27da26ed23..ddd6d9a25da 100644 --- a/tests/ui/rfcs/rfc-3348-c-string-literals/gate.rs +++ b/tests/ui/rfcs/rfc-3348-c-string-literals/gate.rs @@ -1,4 +1,6 @@ // gate-test-c_str_literals +// known-bug: #113333 +// edition: 2021 macro_rules! m { ($t:tt) => {} @@ -6,8 +8,8 @@ macro_rules! m { fn main() { c"foo"; - //~^ ERROR: `c".."` literals are experimental + // FIXME(c_str_literals): This should be ``c".."` literals are experimental` m!(c"test"); - //~^ ERROR: `c".."` literals are experimental + // FIXME(c_str_literals): This should be ``c".."` literals are experimental` } diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/gate.stderr b/tests/ui/rfcs/rfc-3348-c-string-literals/gate.stderr index bc0c537aada..8de36ca4a6e 100644 --- a/tests/ui/rfcs/rfc-3348-c-string-literals/gate.stderr +++ b/tests/ui/rfcs/rfc-3348-c-string-literals/gate.stderr @@ -1,21 +1,32 @@ -error[E0658]: `c".."` literals are experimental - --> $DIR/gate.rs:8:5 +error: prefix `c` is unknown + --> $DIR/gate.rs:10:5 | LL | c"foo"; - | ^^^^^^ + | ^ unknown prefix | - = note: see issue #105723 <https://github.com/rust-lang/rust/issues/105723> for more information - = help: add `#![feature(c_str_literals)]` to the crate attributes to enable + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: consider inserting whitespace here + | +LL | c "foo"; + | + -error[E0658]: `c".."` literals are experimental - --> $DIR/gate.rs:11:8 +error: prefix `c` is unknown + --> $DIR/gate.rs:13:8 | LL | m!(c"test"); - | ^^^^^^^ + | ^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: consider inserting whitespace here | - = note: see issue #105723 <https://github.com/rust-lang/rust/issues/105723> for more information - = help: add `#![feature(c_str_literals)]` to the crate attributes to enable +LL | m!(c "test"); + | + + +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"foo"` + --> $DIR/gate.rs:10:6 + | +LL | c"foo"; + | ^^^^^ expected one of 8 possible tokens -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs index 7bc6097f124..96945f125da 100644 --- a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs +++ b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs Binary files differdiff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr index ff9006f6f97..2226c7aa6a9 100644 --- a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr +++ b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr Binary files differdiff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs index 82e8e2090d7..066505c23df 100644 --- a/tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs +++ b/tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs @@ -1,4 +1,6 @@ -// run-pass +// FIXME(c_str_literals): This should be `run-pass` +// known-bug: #113333 +// edition: 2021 #![feature(c_str_literals)] diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.stderr b/tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.stderr new file mode 100644 index 00000000000..47361fb61d2 --- /dev/null +++ b/tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.stderr @@ -0,0 +1,38 @@ +error: prefix `c` is unknown + --> $DIR/non-ascii.rs:9:9 + | +LL | c"\xEF\x80🦀\u{1F980}".to_bytes_with_nul(), + | ^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: consider inserting whitespace here + | +LL | c "\xEF\x80🦀\u{1F980}".to_bytes_with_nul(), + | + + +error: out of range hex escape + --> $DIR/non-ascii.rs:9:11 + | +LL | c"\xEF\x80🦀\u{1F980}".to_bytes_with_nul(), + | ^^^^ must be a character in the range [\x00-\x7f] + +error: out of range hex escape + --> $DIR/non-ascii.rs:9:15 + | +LL | c"\xEF\x80🦀\u{1F980}".to_bytes_with_nul(), + | ^^^^ must be a character in the range [\x00-\x7f] + +error: no rules expected the token `"\xEF\x80🦀\u{1F980}"` + --> $DIR/non-ascii.rs:9:10 + | +LL | c"\xEF\x80🦀\u{1F980}".to_bytes_with_nul(), + | -^^^^^^^^^^^^^^^^^^^^ + | | + | no rules expected this token in macro call + | help: missing comma here + | +note: while trying to match `,` + --> $SRC_DIR/core/src/macros/mod.rs:LL:COL + +error: aborting due to 4 previous errors + diff --git a/tests/ui/suggestions/crate-or-module-typo.stderr b/tests/ui/suggestions/crate-or-module-typo.stderr index 98b88b4fb92..5e7a7685ab0 100644 --- a/tests/ui/suggestions/crate-or-module-typo.stderr +++ b/tests/ui/suggestions/crate-or-module-typo.stderr @@ -36,6 +36,11 @@ error[E0433]: failed to resolve: use of undeclared crate or module `bar` | LL | pub fn bar() { bar::baz(); } | ^^^ use of undeclared crate or module `bar` + | +help: consider importing this module + | +LL + use crate::bar; + | error: aborting due to 4 previous errors diff --git a/tests/ui/suggestions/issue-112590-suggest-import.rs b/tests/ui/suggestions/issue-112590-suggest-import.rs new file mode 100644 index 00000000000..0938814c559 --- /dev/null +++ b/tests/ui/suggestions/issue-112590-suggest-import.rs @@ -0,0 +1,10 @@ +pub struct S; + +impl fmt::Debug for S { //~ ERROR failed to resolve: use of undeclared crate or module `fmt` + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { //~ ERROR failed to resolve: use of undeclared crate or module `fmt` + //~^ ERROR failed to resolve: use of undeclared crate or module `fmt` + Ok(()) + } +} + +fn main() { } diff --git a/tests/ui/suggestions/issue-112590-suggest-import.stderr b/tests/ui/suggestions/issue-112590-suggest-import.stderr new file mode 100644 index 00000000000..aeac18c16f0 --- /dev/null +++ b/tests/ui/suggestions/issue-112590-suggest-import.stderr @@ -0,0 +1,36 @@ +error[E0433]: failed to resolve: use of undeclared crate or module `fmt` + --> $DIR/issue-112590-suggest-import.rs:3:6 + | +LL | impl fmt::Debug for S { + | ^^^ use of undeclared crate or module `fmt` + | +help: consider importing this module + | +LL + use std::fmt; + | + +error[E0433]: failed to resolve: use of undeclared crate or module `fmt` + --> $DIR/issue-112590-suggest-import.rs:4:28 + | +LL | fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + | ^^^ use of undeclared crate or module `fmt` + | +help: consider importing this module + | +LL + use std::fmt; + | + +error[E0433]: failed to resolve: use of undeclared crate or module `fmt` + --> $DIR/issue-112590-suggest-import.rs:4:51 + | +LL | fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + | ^^^ use of undeclared crate or module `fmt` + | +help: consider importing this module + | +LL + use std::fmt; + | + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/suggestions/issue-89640.rs b/tests/ui/suggestions/issue-89640.rs new file mode 100644 index 00000000000..6bb33ad8f30 --- /dev/null +++ b/tests/ui/suggestions/issue-89640.rs @@ -0,0 +1,3 @@ +fn main() { + le t x: i32 = 3; //~ ERROR expected one of +} diff --git a/tests/ui/suggestions/issue-89640.stderr b/tests/ui/suggestions/issue-89640.stderr new file mode 100644 index 00000000000..8ff4ef4f0ec --- /dev/null +++ b/tests/ui/suggestions/issue-89640.stderr @@ -0,0 +1,13 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `t` + --> $DIR/issue-89640.rs:2:8 + | +LL | le t x: i32 = 3; + | ^ expected one of 8 possible tokens + | +help: consider removing the space to spell keyword `let` + | +LL | let x: i32 = 3; + | ~~~ + +error: aborting due to previous error + diff --git a/tests/ui/traits/new-solver/alias-bound-unsound.rs b/tests/ui/traits/new-solver/alias-bound-unsound.rs index 6b6a77e2c7e..959f1afa04e 100644 --- a/tests/ui/traits/new-solver/alias-bound-unsound.rs +++ b/tests/ui/traits/new-solver/alias-bound-unsound.rs @@ -21,9 +21,7 @@ impl Foo for () { fn main() { let x = String::from("hello, world"); drop(<() as Foo>::copy_me(&x)); - //~^ ERROR `<() as Foo>::Item: Copy` is not satisfied - //~| ERROR `<() as Foo>::Item` is not well-formed - //~| ERROR `<() as Foo>::Item` is not well-formed + //~^ ERROR the type `&<() as Foo>::Item` is not well-formed //~| ERROR `<() as Foo>::Item` is not well-formed println!("{x}"); } diff --git a/tests/ui/traits/new-solver/alias-bound-unsound.stderr b/tests/ui/traits/new-solver/alias-bound-unsound.stderr index 89abc608213..5800e2c4340 100644 --- a/tests/ui/traits/new-solver/alias-bound-unsound.stderr +++ b/tests/ui/traits/new-solver/alias-bound-unsound.stderr @@ -1,29 +1,8 @@ -error[E0277]: the trait bound `<() as Foo>::Item: Copy` is not satisfied - --> $DIR/alias-bound-unsound.rs:23:10 - | -LL | drop(<() as Foo>::copy_me(&x)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `<() as Foo>::Item` - | -note: required by a bound in `Foo::Item` - --> $DIR/alias-bound-unsound.rs:10:30 - | -LL | type Item: Copy - | ---- required by a bound in this associated type -LL | where -LL | <Self as Foo>::Item: Copy; - | ^^^^ required by this bound in `Foo::Item` - -error: the type `<() as Foo>::Item` is not well-formed - --> $DIR/alias-bound-unsound.rs:23:10 - | -LL | drop(<() as Foo>::copy_me(&x)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: the type `<() as Foo>::Item` is not well-formed - --> $DIR/alias-bound-unsound.rs:23:5 +error: the type `&<() as Foo>::Item` is not well-formed + --> $DIR/alias-bound-unsound.rs:23:31 | LL | drop(<() as Foo>::copy_me(&x)); - | ^^^^ + | ^^ error: the type `<() as Foo>::Item` is not well-formed --> $DIR/alias-bound-unsound.rs:23:10 @@ -31,6 +10,5 @@ error: the type `<() as Foo>::Item` is not well-formed LL | drop(<() as Foo>::copy_me(&x)); | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.rs b/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.rs index b036411be83..204f6e8b071 100644 --- a/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.rs +++ b/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.rs @@ -1,22 +1,17 @@ // compile-flags: -Ztrait-solver=next -// check-pass -// (should not pass, should be turned into a coherence-only test) - -// check that a `alias-eq(<?0 as TraitB>::Assoc, <T as TraitB>::Assoc)` goal fails. - -// FIXME(deferred_projection_equality): add a test that this is true during coherence +// check that a `alias-eq(<?a as TraitB>::Assoc, <?b as TraitB>::Assoc)` goal fails +// during coherence. We must not incorrectly constrain `?a` and `?b` to be +// equal. trait TraitB { type Assoc; } -fn needs_a<T: TraitB>() -> T::Assoc { - unimplemented!() -} +trait Overlaps<T> {} -fn bar<T: TraitB>() { - let _: <_ as TraitB>::Assoc = needs_a::<T>(); -} +impl<T: TraitB> Overlaps<Box<T>> for <T as TraitB>::Assoc {} +impl<U: TraitB> Overlaps<U> for <U as TraitB>::Assoc {} +//~^ ERROR conflicting implementations of trait fn main() {} diff --git a/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.stderr b/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.stderr new file mode 100644 index 00000000000..8eda64e4490 --- /dev/null +++ b/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.stderr @@ -0,0 +1,11 @@ +error[E0119]: conflicting implementations of trait `Overlaps<Box<_>>` for type `<_ as TraitB>::Assoc` + --> $DIR/alias_eq_substs_eq_not_intercrate.rs:14:1 + | +LL | impl<T: TraitB> Overlaps<Box<T>> for <T as TraitB>::Assoc {} + | --------------------------------------------------------- first implementation here +LL | impl<U: TraitB> Overlaps<U> for <U as TraitB>::Assoc {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `<_ as TraitB>::Assoc` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/new-solver/async.fail.stderr b/tests/ui/traits/new-solver/async.fail.stderr index b395c23ae00..72fa2eb3161 100644 --- a/tests/ui/traits/new-solver/async.fail.stderr +++ b/tests/ui/traits/new-solver/async.fail.stderr @@ -1,8 +1,8 @@ -error[E0271]: expected `[async block@$DIR/async.rs:12:17: 12:25]` to be a future that resolves to `i32`, but it resolves to `()` +error[E0271]: type mismatch resolving `<[async block@$DIR/async.rs:12:17: 12:25] as Future>::Output == i32` --> $DIR/async.rs:12:17 | LL | needs_async(async {}); - | ----------- ^^^^^^^^ expected `i32`, found `()` + | ----------- ^^^^^^^^ types differ | | | required by a bound introduced by this call | diff --git a/tests/ui/traits/new-solver/async.rs b/tests/ui/traits/new-solver/async.rs index 195cc35cad2..155b71eb749 100644 --- a/tests/ui/traits/new-solver/async.rs +++ b/tests/ui/traits/new-solver/async.rs @@ -10,7 +10,7 @@ fn needs_async(_: impl Future<Output = i32>) {} #[cfg(fail)] fn main() { needs_async(async {}); - //[fail]~^ ERROR to be a future that resolves to `i32`, but it resolves to `()` + //[fail]~^ ERROR type mismatch } #[cfg(pass)] diff --git a/tests/ui/traits/new-solver/dont-type_of-tait-in-defining-scope.not_send.stderr b/tests/ui/traits/new-solver/dont-type_of-tait-in-defining-scope.not_send.stderr new file mode 100644 index 00000000000..ec1c3231abc --- /dev/null +++ b/tests/ui/traits/new-solver/dont-type_of-tait-in-defining-scope.not_send.stderr @@ -0,0 +1,16 @@ +error[E0283]: type annotations needed: cannot satisfy `Foo: Send` + --> $DIR/dont-type_of-tait-in-defining-scope.rs:16:5 + | +LL | needs_send::<Foo>(); + | ^^^^^^^^^^^^^^^^^ + | + = note: cannot satisfy `Foo: Send` +note: required by a bound in `needs_send` + --> $DIR/dont-type_of-tait-in-defining-scope.rs:13:18 + | +LL | fn needs_send<T: Send>() {} + | ^^^^ required by this bound in `needs_send` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/traits/new-solver/dont-type_of-tait-in-defining-scope.rs b/tests/ui/traits/new-solver/dont-type_of-tait-in-defining-scope.rs new file mode 100644 index 00000000000..5a0dcd0e8cc --- /dev/null +++ b/tests/ui/traits/new-solver/dont-type_of-tait-in-defining-scope.rs @@ -0,0 +1,22 @@ +// revisions: is_send not_send +// compile-flags: -Ztrait-solver=next +//[is_send] check-pass + +#![feature(type_alias_impl_trait)] + +#[cfg(is_send)] +type Foo = impl Send; + +#[cfg(not_send)] +type Foo = impl Sized; + +fn needs_send<T: Send>() {} + +fn test() { + needs_send::<Foo>(); + //[not_send]~^ ERROR type annotations needed: cannot satisfy `Foo: Send` +} + +fn main() { + let _: Foo = (); +} diff --git a/tests/ui/traits/new-solver/dyn-any-dont-prefer-impl.rs b/tests/ui/traits/new-solver/dyn-any-dont-prefer-impl.rs new file mode 100644 index 00000000000..7d15b8c6392 --- /dev/null +++ b/tests/ui/traits/new-solver/dyn-any-dont-prefer-impl.rs @@ -0,0 +1,13 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +use std::any::Any; + +fn needs_usize(_: &usize) {} + +fn main() { + let x: &dyn Any = &1usize; + if let Some(x) = x.downcast_ref::<usize>() { + needs_usize(x); + } +} diff --git a/tests/ui/traits/new-solver/equating-projection-cyclically.rs b/tests/ui/traits/new-solver/equating-projection-cyclically.rs index 019c6e81c50..2668da1b745 100644 --- a/tests/ui/traits/new-solver/equating-projection-cyclically.rs +++ b/tests/ui/traits/new-solver/equating-projection-cyclically.rs @@ -1,11 +1,10 @@ // compile-flags: -Ztrait-solver=next -// known-bug: unknown trait Test { type Assoc; } -fn transform<T: Test>(x: T) -> T::Assoc { +fn transform<T: Test>(x: Inv<T>) -> Inv<T::Assoc> { todo!() } @@ -17,8 +16,13 @@ impl Test for String { type Assoc = String; } +struct Inv<T>(Option<*mut T>); + fn main() { - let mut x = Default::default(); + let mut x: Inv<_> = Inv(None); + // This ends up equating `Inv<?x>` with `Inv<<?x as Test>::Assoc>` + // which fails the occurs check when generalizing `?x`. x = transform(x); - x = 1i32; + //~^ ERROR mismatched types + x = Inv::<i32>(None); } diff --git a/tests/ui/traits/new-solver/equating-projection-cyclically.stderr b/tests/ui/traits/new-solver/equating-projection-cyclically.stderr index 57cbc65a17a..6031d4f08ee 100644 --- a/tests/ui/traits/new-solver/equating-projection-cyclically.stderr +++ b/tests/ui/traits/new-solver/equating-projection-cyclically.stderr @@ -1,13 +1,8 @@ error[E0308]: mismatched types - --> $DIR/equating-projection-cyclically.rs:22:19 + --> $DIR/equating-projection-cyclically.rs:25:9 | LL | x = transform(x); - | ^ expected inferred type, found associated type - | - = note: expected type `_` - found associated type `<_ as Test>::Assoc` - = help: consider constraining the associated type `<_ as Test>::Assoc` to `_` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + | ^^^^^^^^^^^^ cyclic type of infinite size error: aborting due to previous error diff --git a/tests/ui/traits/new-solver/lazy-nested-obligations-2.rs b/tests/ui/traits/new-solver/lazy-nested-obligations-2.rs index 32addd829dc..fd91d81cdf0 100644 --- a/tests/ui/traits/new-solver/lazy-nested-obligations-2.rs +++ b/tests/ui/traits/new-solver/lazy-nested-obligations-2.rs @@ -1,6 +1,5 @@ -// check-pass // compile-flags: -Ztrait-solver=next -// Issue 95863 +// known-bug: #95863 pub trait With { type F; diff --git a/tests/ui/traits/new-solver/lazy-nested-obligations-2.stderr b/tests/ui/traits/new-solver/lazy-nested-obligations-2.stderr new file mode 100644 index 00000000000..d0a4cd661b3 --- /dev/null +++ b/tests/ui/traits/new-solver/lazy-nested-obligations-2.stderr @@ -0,0 +1,39 @@ +error[E0308]: mismatched types + --> $DIR/lazy-nested-obligations-2.rs:15:23 + | +LL | let _: V<i32> = V(f); + | - ^ types differ + | | + | arguments to this struct are incorrect + | + = note: expected associated type `<i32 as With>::F` + found fn item `for<'a> fn(&'a str) {f}` + = help: consider constraining the associated type `<i32 as With>::F` to `for<'a> fn(&'a str) {f}` or calling a method that returns `<i32 as With>::F` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html +note: tuple struct defined here + --> $DIR/lazy-nested-obligations-2.rs:16:16 + | +LL | pub struct V<T: With>(<T as With>::F); + | ^ + +error[E0308]: mismatched types + --> $DIR/lazy-nested-obligations-2.rs:21:30 + | +LL | let _: E3<i32> = E3::Var(f); + | ------- ^ types differ + | | + | arguments to this enum variant are incorrect + | + = note: expected associated type `<i32 as With>::F` + found fn item `for<'a> fn(&'a str) {f}` + = help: consider constraining the associated type `<i32 as With>::F` to `for<'a> fn(&'a str) {f}` or calling a method that returns `<i32 as With>::F` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html +note: tuple variant defined here + --> $DIR/lazy-nested-obligations-2.rs:19:9 + | +LL | Var(<T as With>::F), + | ^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/new-solver/object-unsafety.rs b/tests/ui/traits/new-solver/object-unsafety.rs index 7bdd863a762..da843c91478 100644 --- a/tests/ui/traits/new-solver/object-unsafety.rs +++ b/tests/ui/traits/new-solver/object-unsafety.rs @@ -10,7 +10,15 @@ fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From { pub fn copy_any<T>(t: &T) -> T { copy::<dyn Setup<From=T>>(t) - //~^ ERROR the trait bound `dyn Setup<From = T>: Setup` is not satisfied + //~^ ERROR the type `&<dyn Setup<From = T> as Setup>::From` is not well-formed + //~| ERROR the trait bound `dyn Setup<From = T>: Setup` is not satisfied + //~| ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR the type `<dyn Setup<From = T> as Setup>::From` is not well-formed + //~| ERROR the size for values of type `<dyn Setup<From = T> as Setup>::From` cannot be known at compilation time + + // FIXME(-Ztrait-solver=next): These error messages are horrible and some of them + // are even simple fallout from previous error. } fn main() { diff --git a/tests/ui/traits/new-solver/object-unsafety.stderr b/tests/ui/traits/new-solver/object-unsafety.stderr index 198ac623df8..bb7c68b8941 100644 --- a/tests/ui/traits/new-solver/object-unsafety.stderr +++ b/tests/ui/traits/new-solver/object-unsafety.stderr @@ -14,6 +14,65 @@ help: consider introducing a `where` clause, but there might be an alternative b LL | pub fn copy_any<T>(t: &T) -> T where dyn Setup<From = T>: Setup { | ++++++++++++++++++++++++++++++++ -error: aborting due to previous error +error: the type `&<dyn Setup<From = T> as Setup>::From` is not well-formed + --> $DIR/object-unsafety.rs:12:31 + | +LL | copy::<dyn Setup<From=T>>(t) + | ^ + +error[E0308]: mismatched types + --> $DIR/object-unsafety.rs:12:31 + | +LL | copy::<dyn Setup<From=T>>(t) + | ------------------------- ^ types differ + | | + | arguments to this function are incorrect + | + = note: expected reference `&<dyn Setup<From = T> as Setup>::From` + found reference `&T` +note: function defined here + --> $DIR/object-unsafety.rs:7:4 + | +LL | fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From { + | ^^^^ -------------- + +error[E0308]: mismatched types + --> $DIR/object-unsafety.rs:12:5 + | +LL | pub fn copy_any<T>(t: &T) -> T { + | - - expected `T` because of return type + | | + | this type parameter +LL | copy::<dyn Setup<From=T>>(t) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ + | + = note: expected type parameter `T` + found associated type `<dyn Setup<From = T> as Setup>::From` + = note: you might be missing a type parameter or trait bound + +error: the type `<dyn Setup<From = T> as Setup>::From` is not well-formed + --> $DIR/object-unsafety.rs:12:5 + | +LL | copy::<dyn Setup<From=T>>(t) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the size for values of type `<dyn Setup<From = T> as Setup>::From` cannot be known at compilation time + --> $DIR/object-unsafety.rs:12:5 + | +LL | copy::<dyn Setup<From=T>>(t) + | ^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | doesn't have a size known at compile-time + | this returned value is of type `<dyn Setup<From = T> as Setup>::From` + | + = help: the trait `Sized` is not implemented for `<dyn Setup<From = T> as Setup>::From` + = note: the return type of a function must have a statically known size +help: consider further restricting the associated type + | +LL | pub fn copy_any<T>(t: &T) -> T where <dyn Setup<From = T> as Setup>::From: Sized { + | +++++++++++++++++++++++++++++++++++++++++++++++++ + +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/new-solver/recursive-self-normalization-2.rs b/tests/ui/traits/new-solver/recursive-self-normalization-2.rs index 8c029f5179d..d086db475ac 100644 --- a/tests/ui/traits/new-solver/recursive-self-normalization-2.rs +++ b/tests/ui/traits/new-solver/recursive-self-normalization-2.rs @@ -1,3 +1,4 @@ +//~ ERROR overflow // compile-flags: -Ztrait-solver=next trait Foo1 { diff --git a/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr b/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr index 139b0a45680..eebaf21d7df 100644 --- a/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr +++ b/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr @@ -1,16 +1,20 @@ error[E0275]: overflow evaluating the requirement `<T as Foo1>::Assoc1: Bar` - --> $DIR/recursive-self-normalization-2.rs:15:5 + --> $DIR/recursive-self-normalization-2.rs:16:5 | LL | needs_bar::<T::Assoc1>(); | ^^^^^^^^^^^^^^^^^^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization_2`) note: required by a bound in `needs_bar` - --> $DIR/recursive-self-normalization-2.rs:12:17 + --> $DIR/recursive-self-normalization-2.rs:13:17 | LL | fn needs_bar<S: Bar>() {} | ^^^ required by this bound in `needs_bar` -error: aborting due to previous error +error[E0275]: overflow evaluating the requirement `<T as Foo2>::Assoc2` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization_2`) + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/new-solver/recursive-self-normalization.rs b/tests/ui/traits/new-solver/recursive-self-normalization.rs index 06d187b5fdf..d15df7dea73 100644 --- a/tests/ui/traits/new-solver/recursive-self-normalization.rs +++ b/tests/ui/traits/new-solver/recursive-self-normalization.rs @@ -1,3 +1,4 @@ +//~ ERROR overflow evaluating the requirement `<T as Foo>::Assoc` [E0275] // compile-flags: -Ztrait-solver=next trait Foo { diff --git a/tests/ui/traits/new-solver/recursive-self-normalization.stderr b/tests/ui/traits/new-solver/recursive-self-normalization.stderr index 8e9b9b4b4ce..6a87fe2f121 100644 --- a/tests/ui/traits/new-solver/recursive-self-normalization.stderr +++ b/tests/ui/traits/new-solver/recursive-self-normalization.stderr @@ -1,16 +1,20 @@ error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc: Bar` - --> $DIR/recursive-self-normalization.rs:11:5 + --> $DIR/recursive-self-normalization.rs:12:5 | LL | needs_bar::<T::Assoc>(); | ^^^^^^^^^^^^^^^^^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization`) note: required by a bound in `needs_bar` - --> $DIR/recursive-self-normalization.rs:8:17 + --> $DIR/recursive-self-normalization.rs:9:17 | LL | fn needs_bar<S: Bar>() {} | ^^^ required by this bound in `needs_bar` -error: aborting due to previous error +error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization`) + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/new-solver/slice-match-byte-lit.stderr b/tests/ui/traits/new-solver/slice-match-byte-lit.stderr index 294e8bc94be..cd48a6d1843 100644 --- a/tests/ui/traits/new-solver/slice-match-byte-lit.stderr +++ b/tests/ui/traits/new-solver/slice-match-byte-lit.stderr @@ -1,8 +1,8 @@ -error[E0271]: type mismatch resolving `[u8; 3] <: <Range<usize> as SliceIndex<[u8]>>::Output` +error[E0271]: type mismatch resolving `[u8; 3] <: <[u8] as Index<Range<usize>>>::Output` --> $DIR/slice-match-byte-lit.rs:6:9 | LL | match &s[0..3] { - | -------- this expression has type `&<std::ops::Range<usize> as SliceIndex<[u8]>>::Output` + | -------- this expression has type `&<[u8] as Index<std::ops::Range<usize>>>::Output` LL | b"uwu" => {} | ^^^^^^ types differ diff --git a/tests/ui/traits/new-solver/specialization-transmute.rs b/tests/ui/traits/new-solver/specialization-transmute.rs index a54701df4ef..f6b19e7adf5 100644 --- a/tests/ui/traits/new-solver/specialization-transmute.rs +++ b/tests/ui/traits/new-solver/specialization-transmute.rs @@ -10,12 +10,11 @@ trait Default { } impl<T> Default for T { - default type Id = T; - - fn intu(&self) -> &Self::Id { + default type Id = T; + // This will be fixed by #111994 + fn intu(&self) -> &Self::Id { //~ ERROR type annotations needed self - //~^ ERROR cannot satisfy `T <: <T as Default>::Id` - } + } } fn transmute<T: Default<Id = U>, U: Copy>(t: T) -> U { @@ -24,7 +23,6 @@ fn transmute<T: Default<Id = U>, U: Copy>(t: T) -> U { use std::num::NonZeroU8; fn main() { - let s = transmute::<u8, Option<NonZeroU8>>(0); - //~^ ERROR cannot satisfy `<u8 as Default>::Id == Option<NonZeroU8> + let s = transmute::<u8, Option<NonZeroU8>>(0); // this call should then error assert_eq!(s, None); } diff --git a/tests/ui/traits/new-solver/specialization-transmute.stderr b/tests/ui/traits/new-solver/specialization-transmute.stderr index e67c56afc0d..09b1405fefb 100644 --- a/tests/ui/traits/new-solver/specialization-transmute.stderr +++ b/tests/ui/traits/new-solver/specialization-transmute.stderr @@ -8,24 +8,14 @@ LL | #![feature(specialization)] = help: consider using `min_specialization` instead, which is more stable and complete = note: `#[warn(incomplete_features)]` on by default -error[E0284]: type annotations needed: cannot satisfy `T <: <T as Default>::Id` - --> $DIR/specialization-transmute.rs:16:9 +error[E0284]: type annotations needed + --> $DIR/specialization-transmute.rs:15:23 | -LL | self - | ^^^^ cannot satisfy `T <: <T as Default>::Id` - -error[E0284]: type annotations needed: cannot satisfy `<u8 as Default>::Id == Option<NonZeroU8>` - --> $DIR/specialization-transmute.rs:27:13 - | -LL | let s = transmute::<u8, Option<NonZeroU8>>(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `<u8 as Default>::Id == Option<NonZeroU8>` - | -note: required by a bound in `transmute` - --> $DIR/specialization-transmute.rs:21:25 +LL | fn intu(&self) -> &Self::Id { + | ^^^^^^^^^ cannot infer type | -LL | fn transmute<T: Default<Id = U>, U: Copy>(t: T) -> U { - | ^^^^^^ required by this bound in `transmute` + = note: cannot satisfy `<T as Default>::Id == _` -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/traits/new-solver/specialization-unconstrained.rs b/tests/ui/traits/new-solver/specialization-unconstrained.rs index 02150689ee5..7fd753109be 100644 --- a/tests/ui/traits/new-solver/specialization-unconstrained.rs +++ b/tests/ui/traits/new-solver/specialization-unconstrained.rs @@ -11,7 +11,7 @@ trait Default { } impl<T> Default for T { - default type Id = T; + default type Id = T; //~ ERROR type annotations needed } fn test<T: Default<Id = U>, U>() {} diff --git a/tests/ui/traits/new-solver/specialization-unconstrained.stderr b/tests/ui/traits/new-solver/specialization-unconstrained.stderr index 910925cbaeb..9915da1a27a 100644 --- a/tests/ui/traits/new-solver/specialization-unconstrained.stderr +++ b/tests/ui/traits/new-solver/specialization-unconstrained.stderr @@ -8,6 +8,12 @@ LL | #![feature(specialization)] = help: consider using `min_specialization` instead, which is more stable and complete = note: `#[warn(incomplete_features)]` on by default +error[E0282]: type annotations needed + --> $DIR/specialization-unconstrained.rs:14:22 + | +LL | default type Id = T; + | ^ cannot infer type for associated type `<T as Default>::Id` + error[E0284]: type annotations needed: cannot satisfy `<u32 as Default>::Id == ()` --> $DIR/specialization-unconstrained.rs:20:5 | @@ -20,6 +26,7 @@ note: required by a bound in `test` LL | fn test<T: Default<Id = U>, U>() {} | ^^^^^^ required by this bound in `test` -error: aborting due to previous error; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0284`. +Some errors have detailed explanations: E0282, E0284. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/traits/new-solver/winnow-specializing-impls.rs b/tests/ui/traits/new-solver/winnow-specializing-impls.rs new file mode 100644 index 00000000000..06f64de7403 --- /dev/null +++ b/tests/ui/traits/new-solver/winnow-specializing-impls.rs @@ -0,0 +1,22 @@ +// build-pass +// compile-flags: -Ztrait-solver=next + +// Tests that the specializing impl `<() as Foo>` holds during codegen. + +#![feature(min_specialization)] + +trait Foo { + fn bar(); +} + +impl<T> Foo for T { + default fn bar() {} +} + +impl Foo for () { + fn bar() {} +} + +fn main() { + <() as Foo>::bar(); +} diff --git a/tests/ui/type-alias-impl-trait/auto-trait-leakage3.rs b/tests/ui/type-alias-impl-trait/auto-trait-leakage3.rs index 5fb7a9473d3..fd3f9c61420 100644 --- a/tests/ui/type-alias-impl-trait/auto-trait-leakage3.rs +++ b/tests/ui/type-alias-impl-trait/auto-trait-leakage3.rs @@ -4,8 +4,9 @@ // FIXME This should compile, but it currently doesn't mod m { - type Foo = impl std::fmt::Debug; + pub type Foo = impl std::fmt::Debug; //~^ ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391] + //~| ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391] pub fn foo() -> Foo { 22_u32 @@ -13,6 +14,7 @@ mod m { pub fn bar() { is_send(foo()); + //~^ ERROR: cannot check whether the hidden type of `auto_trait_leakage3[211d]::m::Foo::{opaque#0} } fn is_send<T: Send>(_: T) {} diff --git a/tests/ui/type-alias-impl-trait/auto-trait-leakage3.stderr b/tests/ui/type-alias-impl-trait/auto-trait-leakage3.stderr index 1e9a45aac79..dd56c59bf5f 100644 --- a/tests/ui/type-alias-impl-trait/auto-trait-leakage3.stderr +++ b/tests/ui/type-alias-impl-trait/auto-trait-leakage3.stderr @@ -1,11 +1,11 @@ error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}` - --> $DIR/auto-trait-leakage3.rs:7:16 + --> $DIR/auto-trait-leakage3.rs:7:20 | -LL | type Foo = impl std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^ +LL | pub type Foo = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^ | note: ...which requires type-checking `m::bar`... - --> $DIR/auto-trait-leakage3.rs:15:9 + --> $DIR/auto-trait-leakage3.rs:16:9 | LL | is_send(foo()); | ^^^^^^^ @@ -17,6 +17,48 @@ note: cycle used when checking item types in module `m` LL | mod m { | ^^^^^ -error: aborting due to previous error +error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}` + --> $DIR/auto-trait-leakage3.rs:7:20 + | +LL | pub type Foo = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires type-checking `m::bar`... + --> $DIR/auto-trait-leakage3.rs:15:5 + | +LL | pub fn bar() { + | ^^^^^^^^^^^^ + = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle +note: cycle used when checking item types in module `m` + --> $DIR/auto-trait-leakage3.rs:6:1 + | +LL | mod m { + | ^^^^^ + +error: cannot check whether the hidden type of `auto_trait_leakage3[211d]::m::Foo::{opaque#0}` satisfies auto traits + --> $DIR/auto-trait-leakage3.rs:16:17 + | +LL | is_send(foo()); + | ------- ^^^^^ + | | + | required by a bound introduced by this call + | +note: opaque type is declared here + --> $DIR/auto-trait-leakage3.rs:7:20 + | +LL | pub type Foo = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^ +note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule + --> $DIR/auto-trait-leakage3.rs:15:12 + | +LL | pub fn bar() { + | ^^^ +note: required by a bound in `is_send` + --> $DIR/auto-trait-leakage3.rs:20:19 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/type-alias-impl-trait/cross_inference.rs b/tests/ui/type-alias-impl-trait/cross_inference.rs index 07f3dd1997b..5eaf0ddda99 100644 --- a/tests/ui/type-alias-impl-trait/cross_inference.rs +++ b/tests/ui/type-alias-impl-trait/cross_inference.rs @@ -5,8 +5,8 @@ #![feature(type_alias_impl_trait)] fn main() { - type T = impl Copy; - let foo: T = (1u32, 2u32); + type Tait = impl Copy; + let foo: Tait = (1u32, 2u32); let x: (_, _) = foo; println!("{:?}", x); } diff --git a/tests/ui/type-alias-impl-trait/inference-cycle.rs b/tests/ui/type-alias-impl-trait/inference-cycle.rs index 79caddf7913..093afc25249 100644 --- a/tests/ui/type-alias-impl-trait/inference-cycle.rs +++ b/tests/ui/type-alias-impl-trait/inference-cycle.rs @@ -2,8 +2,9 @@ #![allow(dead_code)] mod m { - type Foo = impl std::fmt::Debug; + pub type Foo = impl std::fmt::Debug; //~^ ERROR cycle detected + //~| ERROR cycle detected // Cycle: error today, but it'd be nice if it eventually worked @@ -13,10 +14,11 @@ mod m { pub fn bar() { is_send(foo()); // Today: error + //~^ ERROR: cannot check whether the hidden type of `inference_cycle[4ecc]::m::Foo::{opaque#0}` satisfies auto traits } fn baz() { - let f: Foo = 22_u32; + let f: Foo = (); } fn is_send<T: Send>(_: T) {} diff --git a/tests/ui/type-alias-impl-trait/inference-cycle.stderr b/tests/ui/type-alias-impl-trait/inference-cycle.stderr index b9d646b927a..4d5f367476b 100644 --- a/tests/ui/type-alias-impl-trait/inference-cycle.stderr +++ b/tests/ui/type-alias-impl-trait/inference-cycle.stderr @@ -1,11 +1,11 @@ error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}` - --> $DIR/inference-cycle.rs:5:16 + --> $DIR/inference-cycle.rs:5:20 | -LL | type Foo = impl std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^ +LL | pub type Foo = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^ | note: ...which requires type-checking `m::bar`... - --> $DIR/inference-cycle.rs:15:9 + --> $DIR/inference-cycle.rs:16:9 | LL | is_send(foo()); // Today: error | ^^^^^^^ @@ -17,6 +17,48 @@ note: cycle used when checking item types in module `m` LL | mod m { | ^^^^^ -error: aborting due to previous error +error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}` + --> $DIR/inference-cycle.rs:5:20 + | +LL | pub type Foo = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires type-checking `m::bar`... + --> $DIR/inference-cycle.rs:15:5 + | +LL | pub fn bar() { + | ^^^^^^^^^^^^ + = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle +note: cycle used when checking item types in module `m` + --> $DIR/inference-cycle.rs:4:1 + | +LL | mod m { + | ^^^^^ + +error: cannot check whether the hidden type of `inference_cycle[4ecc]::m::Foo::{opaque#0}` satisfies auto traits + --> $DIR/inference-cycle.rs:16:17 + | +LL | is_send(foo()); // Today: error + | ------- ^^^^^ + | | + | required by a bound introduced by this call + | +note: opaque type is declared here + --> $DIR/inference-cycle.rs:5:20 + | +LL | pub type Foo = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^ +note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule + --> $DIR/inference-cycle.rs:15:12 + | +LL | pub fn bar() { + | ^^^ +note: required by a bound in `is_send` + --> $DIR/inference-cycle.rs:24:19 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/type-alias-impl-trait/issue-109054.rs b/tests/ui/type-alias-impl-trait/issue-109054.rs new file mode 100644 index 00000000000..1fbec47b14b --- /dev/null +++ b/tests/ui/type-alias-impl-trait/issue-109054.rs @@ -0,0 +1,22 @@ +// edition:2021 + +#![feature(type_alias_impl_trait)] + +struct CallMe; + +type ReturnType<'a> = impl std::future::Future<Output = u32> + 'a; +type FnType = impl Fn(&u32) -> ReturnType; + +impl std::ops::Deref for CallMe { + type Target = FnType; + + fn deref(&self) -> &Self::Target { + fn inner(val: &u32) -> ReturnType { + async move { *val * 2 } + } + + &inner //~ ERROR: expected generic lifetime parameter, found `'_` + } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-109054.stderr b/tests/ui/type-alias-impl-trait/issue-109054.stderr new file mode 100644 index 00000000000..a611b9fe448 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/issue-109054.stderr @@ -0,0 +1,12 @@ +error[E0792]: expected generic lifetime parameter, found `'_` + --> $DIR/issue-109054.rs:18:9 + | +LL | type ReturnType<'a> = impl std::future::Future<Output = u32> + 'a; + | -- this generic parameter must be used with a generic lifetime parameter +... +LL | &inner + | ^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/reveal_local.rs b/tests/ui/type-alias-impl-trait/reveal_local.rs index 7ecb5535301..75015e41c3d 100644 --- a/tests/ui/type-alias-impl-trait/reveal_local.rs +++ b/tests/ui/type-alias-impl-trait/reveal_local.rs @@ -4,13 +4,16 @@ use std::fmt::Debug; type Foo = impl Debug; //~^ ERROR cycle detected +//~| ERROR cycle detected +//~| ERROR cycle detected -fn is_send<T: Send>() { } +fn is_send<T: Send>() {} fn not_good() { // Error: this function does not constrain `Foo` to any particular // hidden type, so it cannot rely on `Send` being true. is_send::<Foo>(); + //~^ ERROR: cannot check whether the hidden type of `reveal_local[9507]::Foo::{opaque#0}` satisfies auto traits } fn not_gooder() { @@ -20,6 +23,7 @@ fn not_gooder() { // while we could know this from the hidden type, it would // need extra roundabout logic to support it. is_send::<Foo>(); + //~^ ERROR: cannot check whether the hidden type of `reveal_local[9507]::Foo::{opaque#0}` satisfies auto traits } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/reveal_local.stderr b/tests/ui/type-alias-impl-trait/reveal_local.stderr index 27fded33329..202a87ecbb7 100644 --- a/tests/ui/type-alias-impl-trait/reveal_local.stderr +++ b/tests/ui/type-alias-impl-trait/reveal_local.stderr @@ -5,7 +5,7 @@ LL | type Foo = impl Debug; | ^^^^^^^^^^ | note: ...which requires type-checking `not_good`... - --> $DIR/reveal_local.rs:13:5 + --> $DIR/reveal_local.rs:15:5 | LL | is_send::<Foo>(); | ^^^^^^^^^^^^^^ @@ -23,6 +23,98 @@ LL | | LL | | fn main() {} | |____________^ -error: aborting due to previous error +error[E0391]: cycle detected when computing type of `Foo::{opaque#0}` + --> $DIR/reveal_local.rs:5:12 + | +LL | type Foo = impl Debug; + | ^^^^^^^^^^ + | +note: ...which requires type-checking `not_good`... + --> $DIR/reveal_local.rs:12:1 + | +LL | fn not_good() { + | ^^^^^^^^^^^^^ + = note: ...which again requires computing type of `Foo::{opaque#0}`, completing the cycle +note: cycle used when checking item types in top-level module + --> $DIR/reveal_local.rs:1:1 + | +LL | / #![feature(type_alias_impl_trait)] +LL | | +LL | | use std::fmt::Debug; +LL | | +... | +LL | | +LL | | fn main() {} + | |____________^ + +error: cannot check whether the hidden type of `reveal_local[9507]::Foo::{opaque#0}` satisfies auto traits + --> $DIR/reveal_local.rs:15:15 + | +LL | is_send::<Foo>(); + | ^^^ + | +note: opaque type is declared here + --> $DIR/reveal_local.rs:5:12 + | +LL | type Foo = impl Debug; + | ^^^^^^^^^^ +note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule + --> $DIR/reveal_local.rs:12:4 + | +LL | fn not_good() { + | ^^^^^^^^ +note: required by a bound in `is_send` + --> $DIR/reveal_local.rs:10:15 + | +LL | fn is_send<T: Send>() {} + | ^^^^ required by this bound in `is_send` + +error[E0391]: cycle detected when computing type of `Foo::{opaque#0}` + --> $DIR/reveal_local.rs:5:12 + | +LL | type Foo = impl Debug; + | ^^^^^^^^^^ + | +note: ...which requires type-checking `not_gooder`... + --> $DIR/reveal_local.rs:19:1 + | +LL | fn not_gooder() { + | ^^^^^^^^^^^^^^^ + = note: ...which again requires computing type of `Foo::{opaque#0}`, completing the cycle +note: cycle used when checking item types in top-level module + --> $DIR/reveal_local.rs:1:1 + | +LL | / #![feature(type_alias_impl_trait)] +LL | | +LL | | use std::fmt::Debug; +LL | | +... | +LL | | +LL | | fn main() {} + | |____________^ + +error: cannot check whether the hidden type of `reveal_local[9507]::Foo::{opaque#0}` satisfies auto traits + --> $DIR/reveal_local.rs:25:15 + | +LL | is_send::<Foo>(); + | ^^^ + | +note: opaque type is declared here + --> $DIR/reveal_local.rs:5:12 + | +LL | type Foo = impl Debug; + | ^^^^^^^^^^ +note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule + --> $DIR/reveal_local.rs:19:4 + | +LL | fn not_gooder() { + | ^^^^^^^^^^ +note: required by a bound in `is_send` + --> $DIR/reveal_local.rs:10:15 + | +LL | fn is_send<T: Send>() {} + | ^^^^ required by this bound in `is_send` + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/type-inference/issue-113283-alllocator-trait-eq.rs b/tests/ui/type-inference/issue-113283-alllocator-trait-eq.rs new file mode 100644 index 00000000000..5d0e456d9dd --- /dev/null +++ b/tests/ui/type-inference/issue-113283-alllocator-trait-eq.rs @@ -0,0 +1,18 @@ +// run-pass +// Verify that PartialEq implementations do not break type inference when +// accepting types with different allocators + +use std::rc::Rc; +use std::sync::Arc; + + +fn main() { + let boxed: Vec<Box<i32>> = vec![]; + assert_eq!(boxed, vec![]); + + let rc: Vec<Rc<i32>> = vec![]; + assert_eq!(rc, vec![]); + + let arc: Vec<Arc<i32>> = vec![]; + assert_eq!(arc, vec![]); +} |
