From 0be510ee7171c1498b1fcb4278dfa9976154c7bf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 12 Jan 2023 04:19:45 +0000 Subject: [PATCH 01/18] RPITITs are not suggestable --- compiler/rustc_middle/src/ty/diagnostics.rs | 17 +++++++---- .../in-trait/missing-send-bound.rs | 21 ++++++++++++++ .../in-trait/missing-send-bound.stderr | 29 +++++++++++++++++++ 3 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 tests/ui/async-await/in-trait/missing-send-bound.rs create mode 100644 tests/ui/async-await/in-trait/missing-send-bound.stderr diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 8c22df7395f10..638bde27d8c69 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -4,12 +4,13 @@ use std::ops::ControlFlow; use crate::ty::{ visit::TypeVisitable, AliasTy, Const, ConstKind, DefIdTree, InferConst, InferTy, Opaque, - PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, + PolyTraitPredicate, Projection, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, }; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg}; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::WherePredicate; use rustc_span::Span; @@ -443,7 +444,7 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { type BreakTy = (); fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { - match t.kind() { + match *t.kind() { Infer(InferTy::TyVar(_)) if self.infer_suggestable => {} FnDef(..) @@ -458,9 +459,9 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { } Alias(Opaque, AliasTy { def_id, .. }) => { - let parent = self.tcx.parent(*def_id); - if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent) - && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = self.tcx.type_of(parent).kind() + let parent = self.tcx.parent(def_id); + if let DefKind::TyAlias | DefKind::AssocTy = self.tcx.def_kind(parent) + && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = *self.tcx.type_of(parent).kind() && parent_opaque_def_id == def_id { // Okay @@ -469,6 +470,12 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { } } + Alias(Projection, AliasTy { def_id, .. }) => { + if self.tcx.def_kind(def_id) != DefKind::AssocTy { + return ControlFlow::Break(()); + } + } + Param(param) => { // FIXME: It would be nice to make this not use string manipulation, // but it's pretty hard to do this, since `ty::ParamTy` is missing diff --git a/tests/ui/async-await/in-trait/missing-send-bound.rs b/tests/ui/async-await/in-trait/missing-send-bound.rs new file mode 100644 index 0000000000000..78922b59b27b7 --- /dev/null +++ b/tests/ui/async-await/in-trait/missing-send-bound.rs @@ -0,0 +1,21 @@ +// edition:2021 + +#![feature(async_fn_in_trait)] +//~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + +trait Foo { + async fn bar(); +} + +async fn test() { + T::bar().await; +} + +fn test2() { + assert_is_send(test::()); + //~^ ERROR future cannot be sent between threads safely +} + +fn assert_is_send(_: impl Send) {} + +fn main() {} diff --git a/tests/ui/async-await/in-trait/missing-send-bound.stderr b/tests/ui/async-await/in-trait/missing-send-bound.stderr new file mode 100644 index 0000000000000..5cedf3ddb0f68 --- /dev/null +++ b/tests/ui/async-await/in-trait/missing-send-bound.stderr @@ -0,0 +1,29 @@ +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/missing-send-bound.rs:3:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: future cannot be sent between threads safely + --> $DIR/missing-send-bound.rs:15:20 + | +LL | assert_is_send(test::()); + | ^^^^^^^^^^^ future returned by `test` is not `Send` + | + = help: within `impl Future`, the trait `Send` is not implemented for `impl Future` +note: future is not `Send` as it awaits another future which is not `Send` + --> $DIR/missing-send-bound.rs:11:5 + | +LL | T::bar().await; + | ^^^^^^^^ await occurs here on type `impl Future`, which is not `Send` +note: required by a bound in `assert_is_send` + --> $DIR/missing-send-bound.rs:19:27 + | +LL | fn assert_is_send(_: impl Send) {} + | ^^^^ required by this bound in `assert_is_send` + +error: aborting due to previous error; 1 warning emitted + From 59ba74cacb87ac89f7f5fcb5233eaccb50dd8349 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 16 Dec 2022 11:12:59 -0700 Subject: [PATCH 02/18] rustdoc: simplify JS search routine by not messing with lev distance Since the sorting function accounts for an `index` field, there's not much reason to also be applying changes to the levenshtein distance. Instead, we can just not treat `lev` as a filter if there's already a non-sentinel value for `index`. This change gives slightly more weight to the index and path part, as search criteria, than it used to. This changes some of the test cases, but not in any obviously-"worse" way, and, in particular, substring matches are a bigger deal than levenshtein distances (we're assuming that a typo is less likely than someone just not typing the entire name). Based on https://github.com/rust-lang/rust/pull/103710#issuecomment-1296894296 --- src/librustdoc/html/static/js/search.js | 114 +++++++++++++----------- 1 file changed, 64 insertions(+), 50 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 1b8822b0b2b7d..88592fa0c84c1 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -781,7 +781,29 @@ function initSearch(rawSearchIndex) { return a - b; } - // Sort by non levenshtein results and then levenshtein results by the distance + // sort by index of keyword in item name (no literal occurrence goes later) + a = (aaa.index < 0); + b = (bbb.index < 0); + if (a !== b) { + return a - b; + } + + // Sort by distance in the path part, if specified + // (less changes required to match means higher rankings) + a = aaa.path_lev; + b = bbb.path_lev; + if (a !== b) { + return a - b; + } + + // (later literal occurrence, if any, goes later) + a = aaa.index; + b = bbb.index; + if (a !== b) { + return a - b; + } + + // Sort by distance in the name part, the last part of the path // (less changes required to match means higher rankings) a = (aaa.lev); b = (bbb.lev); @@ -810,19 +832,6 @@ function initSearch(rawSearchIndex) { return (a > b ? +1 : -1); } - // sort by index of keyword in item name (no literal occurrence goes later) - a = (aaa.index < 0); - b = (bbb.index < 0); - if (a !== b) { - return a - b; - } - // (later literal occurrence, if any, goes later) - a = aaa.index; - b = bbb.index; - if (a !== b) { - return a - b; - } - // special precedence for primitive and keyword pages if ((aaa.item.ty === TY_PRIMITIVE && bbb.item.ty !== TY_KEYWORD) || (aaa.item.ty === TY_KEYWORD && bbb.item.ty !== TY_PRIMITIVE)) { @@ -1230,15 +1239,19 @@ function initSearch(rawSearchIndex) { * * `id` is the index in both `searchWords` and `searchIndex` arrays for this element. * * `index` is an `integer`` used to sort by the position of the word in the item's name. * * `lev` is the main metric used to sort the search results. + * * `path_lev` is zero if a single-component search query is used, otherwise it's the + * distance computed for everything other than the last path component. * * @param {Results} results * @param {string} fullId * @param {integer} id * @param {integer} index * @param {integer} lev + * @param {integer} path_lev */ - function addIntoResults(results, fullId, id, index, lev) { - if (lev === 0 || (!parsedQuery.literalSearch && lev <= MAX_LEV_DISTANCE)) { + function addIntoResults(results, fullId, id, index, lev, path_lev) { + const inBounds = lev <= MAX_LEV_DISTANCE || index !== -1; + if (lev === 0 || (!parsedQuery.literalSearch && inBounds)) { if (results[fullId] !== undefined) { const result = results[fullId]; if (result.dontValidate || result.lev <= lev) { @@ -1250,6 +1263,7 @@ function initSearch(rawSearchIndex) { index: index, dontValidate: parsedQuery.literalSearch, lev: lev, + path_lev: path_lev, }; } } @@ -1280,68 +1294,68 @@ function initSearch(rawSearchIndex) { if (!row || (filterCrates !== null && row.crate !== filterCrates)) { return; } - let lev, lev_add = 0, index = -1; + let lev, index = -1, path_lev = 0; const fullId = row.id; + const searchWord = searchWords[pos]; const in_args = findArg(row, elem, parsedQuery.typeFilter); const returned = checkReturned(row, elem, parsedQuery.typeFilter); - addIntoResults(results_in_args, fullId, pos, index, in_args); - addIntoResults(results_returned, fullId, pos, index, returned); + // path_lev is 0 because no parent path information is currently stored + // in the search index + addIntoResults(results_in_args, fullId, pos, -1, in_args, 0); + addIntoResults(results_returned, fullId, pos, -1, returned, 0); if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) { return; } - const searchWord = searchWords[pos]; - if (parsedQuery.literalSearch) { - if (searchWord === elem.name) { - addIntoResults(results_others, fullId, pos, -1, 0); - } - return; + const row_index = row.normalizedName.indexOf(elem.pathLast); + const word_index = searchWord.indexOf(elem.pathLast); + + // lower indexes are "better" matches + // rank based on the "best" match + if (row_index === -1) { + index = word_index; + } else if (word_index === -1) { + index = row_index; + } else if (word_index < row_index) { + index = word_index; + } else { + index = row_index; } // No need to check anything else if it's a "pure" generics search. if (elem.name.length === 0) { if (row.type !== null) { lev = checkGenerics(row.type, elem, MAX_LEV_DISTANCE + 1); - addIntoResults(results_others, fullId, pos, index, lev); + // path_lev is 0 because we know it's empty + addIntoResults(results_others, fullId, pos, index, lev, 0); } return; } if (elem.fullPath.length > 1) { - lev = checkPath(elem.pathWithoutLast, row); - if (lev > MAX_LEV_DISTANCE || (parsedQuery.literalSearch && lev !== 0)) { + path_lev = checkPath(elem.pathWithoutLast, row); + if (path_lev > MAX_LEV_DISTANCE) { return; - } else if (lev > 0) { - lev_add = lev / 10; } } - if (searchWord.indexOf(elem.pathLast) > -1 || - row.normalizedName.indexOf(elem.pathLast) > -1 - ) { - index = row.normalizedName.indexOf(elem.pathLast); - } - lev = levenshtein(searchWord, elem.pathLast); - if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1) { - if (elem.pathLast.length < 6) { - lev = 1; - } else { - lev = 0; + if (parsedQuery.literalSearch) { + if (searchWord === elem.name) { + addIntoResults(results_others, fullId, pos, index, 0, path_lev); } - } - lev += lev_add; - if (lev > MAX_LEV_DISTANCE) { return; - } else if (index !== -1 && elem.fullPath.length < 2) { - lev -= 1; } - if (lev < 0) { - lev = 0; + + lev = levenshtein(searchWord, elem.pathLast); + + if (index === -1 && lev + path_lev > MAX_LEV_DISTANCE) { + return; } - addIntoResults(results_others, fullId, pos, index, lev); + + addIntoResults(results_others, fullId, pos, index, lev, path_lev); } /** @@ -1386,7 +1400,7 @@ function initSearch(rawSearchIndex) { return; } const lev = Math.round(totalLev / nbLev); - addIntoResults(results, row.id, pos, 0, lev); + addIntoResults(results, row.id, pos, 0, lev, 0); } function innerRunQuery() { From db558b46861ee2f812ee1cc2b03b796f691a246d Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 16 Dec 2022 13:19:38 -0700 Subject: [PATCH 03/18] rustdoc: update search test cases --- tests/rustdoc-js-std/macro-print.js | 2 +- tests/rustdoc-js-std/typed-query.js | 2 +- tests/rustdoc-js-std/vec-new.js | 5 +++-- tests/rustdoc-js/search-short-types.js | 3 +-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/rustdoc-js-std/macro-print.js b/tests/rustdoc-js-std/macro-print.js index 858046e72e9a4..1b4c7b4057020 100644 --- a/tests/rustdoc-js-std/macro-print.js +++ b/tests/rustdoc-js-std/macro-print.js @@ -3,8 +3,8 @@ const QUERY = 'macro:print'; const EXPECTED = { 'others': [ { 'path': 'std', 'name': 'print' }, - { 'path': 'std', 'name': 'eprint' }, { 'path': 'std', 'name': 'println' }, + { 'path': 'std', 'name': 'eprint' }, { 'path': 'std', 'name': 'eprintln' }, ], }; diff --git a/tests/rustdoc-js-std/typed-query.js b/tests/rustdoc-js-std/typed-query.js index 25efbad269540..fd5c5489d79cf 100644 --- a/tests/rustdoc-js-std/typed-query.js +++ b/tests/rustdoc-js-std/typed-query.js @@ -6,8 +6,8 @@ const FILTER_CRATE = 'std'; const EXPECTED = { 'others': [ { 'path': 'std', 'name': 'print' }, - { 'path': 'std', 'name': 'eprint' }, { 'path': 'std', 'name': 'println' }, + { 'path': 'std', 'name': 'eprint' }, { 'path': 'std', 'name': 'eprintln' }, { 'path': 'std::pin', 'name': 'pin' }, { 'path': 'std::future', 'name': 'join' }, diff --git a/tests/rustdoc-js-std/vec-new.js b/tests/rustdoc-js-std/vec-new.js index cd0e8e7b4a9eb..fc44a566af21f 100644 --- a/tests/rustdoc-js-std/vec-new.js +++ b/tests/rustdoc-js-std/vec-new.js @@ -3,7 +3,8 @@ const QUERY = 'Vec::new'; const EXPECTED = { 'others': [ { 'path': 'std::vec::Vec', 'name': 'new' }, - { 'path': 'std::vec::Vec', 'name': 'ne' }, - { 'path': 'alloc::vec::Vec', 'name': 'ne' }, + { 'path': 'alloc::vec::Vec', 'name': 'new' }, + { 'path': 'std::vec::Vec', 'name': 'new_in' }, + { 'path': 'alloc::vec::Vec', 'name': 'new_in' }, ], }; diff --git a/tests/rustdoc-js/search-short-types.js b/tests/rustdoc-js/search-short-types.js index d14672af71fd6..3b2f15a40bf87 100644 --- a/tests/rustdoc-js/search-short-types.js +++ b/tests/rustdoc-js/search-short-types.js @@ -4,7 +4,6 @@ const EXPECTED = { 'others': [ { 'path': 'search_short_types', 'name': 'P' }, { 'path': 'search_short_types::VeryLongTypeName', 'name': 'p' }, - { 'path': 'search_short_types', 'name': 'Ap' }, - { 'path': 'search_short_types::VeryLongTypeName', 'name': 'ap' }, + { 'path': 'search_short_types', 'name': 'Pa' }, ], }; From 3a4fdcf86cea75796ed947853ea9544f2d11afff Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 15 Jan 2023 20:59:47 +0000 Subject: [PATCH 04/18] Encode const mir for closures if they're const --- compiler/rustc_metadata/src/rmeta/encoder.rs | 13 ++----------- .../ui/consts/auxiliary/closure-in-foreign-crate.rs | 8 ++++++++ tests/ui/consts/closure-in-foreign-crate.rs | 8 ++++++++ 3 files changed, 18 insertions(+), 11 deletions(-) create mode 100644 tests/ui/consts/auxiliary/closure-in-foreign-crate.rs create mode 100644 tests/ui/consts/closure-in-foreign-crate.rs diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index a8000aa3c8a83..e8ae9712a6330 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -888,8 +888,8 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) { | DefKind::AssocConst | DefKind::Static(..) | DefKind::Const => (true, false), - // Full-fledged functions - DefKind::AssocFn | DefKind::Fn => { + // Full-fledged functions + closures + DefKind::AssocFn | DefKind::Fn | DefKind::Closure => { let generics = tcx.generics_of(def_id); let needs_inline = (generics.requires_monomorphization(tcx) || tcx.codegen_fn_attrs(def_id).requests_inline()) @@ -900,15 +900,6 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) { let always_encode_mir = tcx.sess.opts.unstable_opts.always_encode_mir; (is_const_fn, needs_inline || always_encode_mir) } - // Closures can't be const fn. - DefKind::Closure => { - let generics = tcx.generics_of(def_id); - let needs_inline = (generics.requires_monomorphization(tcx) - || tcx.codegen_fn_attrs(def_id).requests_inline()) - && tcx.sess.opts.output_types.should_codegen(); - let always_encode_mir = tcx.sess.opts.unstable_opts.always_encode_mir; - (false, needs_inline || always_encode_mir) - } // Generators require optimized MIR to compute layout. DefKind::Generator => (false, true), // The others don't have MIR. diff --git a/tests/ui/consts/auxiliary/closure-in-foreign-crate.rs b/tests/ui/consts/auxiliary/closure-in-foreign-crate.rs new file mode 100644 index 0000000000000..edc7fa81abb4f --- /dev/null +++ b/tests/ui/consts/auxiliary/closure-in-foreign-crate.rs @@ -0,0 +1,8 @@ +#![crate_type = "lib"] +#![feature(const_closures, const_trait_impl)] +#![allow(incomplete_features)] + +pub const fn test() { + let cl = const || {}; + cl(); +} diff --git a/tests/ui/consts/closure-in-foreign-crate.rs b/tests/ui/consts/closure-in-foreign-crate.rs new file mode 100644 index 0000000000000..fc8f480e706bc --- /dev/null +++ b/tests/ui/consts/closure-in-foreign-crate.rs @@ -0,0 +1,8 @@ +// aux-build:closure-in-foreign-crate.rs +// build-pass + +extern crate closure_in_foreign_crate; + +const _: () = closure_in_foreign_crate::test(); + +fn main() {} From 925dc37313853f15dc21e42dc869b024fe488ef3 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 17 Jan 2023 23:17:13 -0800 Subject: [PATCH 05/18] Stop using `BREAK` & `CONTINUE` in compiler Switching them to `Break(())` and `Continue(())` instead. libs-api would like to remove these constants, so stop using them in compiler to make the removal PR later smaller. --- .../src/const_eval/machine.rs | 8 ++--- .../rustc_const_eval/src/interpret/util.rs | 4 +-- .../src/graph/iterate/mod.rs | 8 ++--- .../rustc_hir_analysis/src/check/check.rs | 6 ++-- .../rustc_hir_analysis/src/check/wfcheck.rs | 2 +- .../src/coherence/orphan.rs | 6 ++-- .../src/constrained_generic_params.rs | 4 +-- .../rustc_hir_analysis/src/variance/mod.rs | 2 +- compiler/rustc_hir_typeck/src/closure.rs | 2 +- .../nice_region_error/static_impl_trait.rs | 2 +- .../rustc_infer/src/infer/nll_relate/mod.rs | 4 +-- .../rustc_infer/src/infer/opaque_types.rs | 10 +++--- compiler/rustc_infer/src/infer/resolve.rs | 4 +-- compiler/rustc_lint/src/types.rs | 2 +- compiler/rustc_macros/src/type_visitable.rs | 2 +- compiler/rustc_middle/src/macros.rs | 8 ++--- .../rustc_middle/src/mir/type_visitable.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 2 +- .../rustc_middle/src/ty/structural_impls.rs | 8 ++--- compiler/rustc_middle/src/ty/sty.rs | 2 +- compiler/rustc_middle/src/ty/visit.rs | 32 +++++++++---------- compiler/rustc_mir_build/src/lints.rs | 6 ++-- .../rustc_monomorphize/src/polymorphize.rs | 14 ++++---- compiler/rustc_privacy/src/lib.rs | 28 +++++++++------- .../src/traits/coherence.rs | 8 ++--- .../src/traits/const_evaluatable.rs | 2 +- .../src/traits/error_reporting/mod.rs | 2 +- .../rustc_trait_selection/src/traits/mod.rs | 6 ++-- .../src/traits/object_safety.rs | 8 ++--- .../src/traits/query/normalize.rs | 6 ++-- .../src/traits/structural_match.rs | 16 +++++----- 31 files changed, 110 insertions(+), 106 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 4f7c1fc96f13f..ca6b01d8a8a7a 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -225,7 +225,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { /// `align_offset(ptr, target_align)` needs special handling in const eval, because the pointer /// may not have an address. /// - /// If `ptr` does have a known address, then we return `CONTINUE` and the function call should + /// If `ptr` does have a known address, then we return `Continue(())` and the function call should /// proceed as normal. /// /// If `ptr` doesn't have an address, but its underlying allocation's alignment is at most @@ -273,18 +273,18 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { ret, StackPopUnwind::NotAllowed, )?; - Ok(ControlFlow::BREAK) + Ok(ControlFlow::Break(())) } else { // Not alignable in const, return `usize::MAX`. let usize_max = Scalar::from_machine_usize(self.machine_usize_max(), self); self.write_scalar(usize_max, dest)?; self.return_to_block(ret)?; - Ok(ControlFlow::BREAK) + Ok(ControlFlow::Break(())) } } Err(_addr) => { // The pointer has an address, continue with function call. - Ok(ControlFlow::CONTINUE) + Ok(ControlFlow::Continue(())) } } } diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index a61d3ab40a5ca..cabc65e2c077e 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -26,7 +26,7 @@ where fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { if !ty.needs_subst() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } match *ty.kind() { @@ -48,7 +48,7 @@ where return subst.visit_with(self); } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => ty.super_visit_with(self), } diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index 57007611a76c3..8a9af300c066e 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -317,12 +317,12 @@ where _node: G::Node, _prior_status: Option, ) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } /// Called after all nodes reachable from this one have been examined. fn node_settled(&mut self, _node: G::Node) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } /// Behave as if no edges exist from `source` to `target`. @@ -346,8 +346,8 @@ where prior_status: Option, ) -> ControlFlow { match prior_status { - Some(NodeStatus::Visited) => ControlFlow::BREAK, - _ => ControlFlow::CONTINUE, + Some(NodeStatus::Visited) => ControlFlow::Break(()), + _ => ControlFlow::Continue(()), } } } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index e58669433e218..d5e4b4cb9e728 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -267,7 +267,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { debug!(?t, "root_visit_ty"); if t == self.opaque_identity_ty { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { t.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { tcx: self.tcx, @@ -282,7 +282,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( if self.references_parent_regions { ControlFlow::Break(t) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -1439,7 +1439,7 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> E match *t.kind() { ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { self.0.push(def); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => t.super_visit_with(self), } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 49dd1eb22f7fe..8739228e207b0 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1428,7 +1428,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id } fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow { - ControlFlow::BREAK + ControlFlow::Break(()) } fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 0aadc9f311b03..0d070f3d118e0 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -416,13 +416,13 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: if t != self.self_ty_root { for impl_def_id in tcx.non_blanket_impls_for_ty(self.trait_def_id, t) { match tcx.impl_polarity(impl_def_id) { - ImplPolarity::Negative => return ControlFlow::BREAK, + ImplPolarity::Negative => return ControlFlow::Break(()), ImplPolarity::Reservation => {} // FIXME(@lcnr): That's probably not good enough, idk // // We might just want to take the rustdoc code and somehow avoid // explicit impls for `Self`. - ImplPolarity::Positive => return ControlFlow::CONTINUE, + ImplPolarity::Positive => return ControlFlow::Continue(()), } } } @@ -440,7 +440,7 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => t.super_visit_with(self), } diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index 95c971c0d7845..56cc1d8fadc00 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -61,7 +61,7 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { match *t.kind() { ty::Alias(ty::Projection, ..) if !self.include_nonconstraining => { // projections are not injective - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } ty::Param(data) => { self.parameters.push(Parameter::from(data)); @@ -76,7 +76,7 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { if let ty::ReEarlyBound(data) = *r { self.parameters.push(Parameter::from(data)); } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 24008f8881433..079070be27983 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -92,7 +92,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc a.visit_with(self)?; } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { substs.visit_with(self) } diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 26e8dd654c13f..12a2abfa76a92 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -236,7 +236,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { if t == self.expected_ty { - ControlFlow::BREAK + ControlFlow::Break(()) } else { t.super_visit_with(self) } 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 fb0f09198ccc1..49ad3ce50b8f5 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 @@ -543,7 +543,7 @@ impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor { if let Some(def_id) = preds.principal_def_id() { self.0.insert(def_id); } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => t.super_visit_with(self), } diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 985cb6463a064..f235cb5ab4503 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -849,7 +849,7 @@ impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { t.super_visit_with(self); self.target_index.shift_out(1); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { @@ -863,7 +863,7 @@ impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { _ => {} } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 6b54ee9576f67..e22ba9785e1fd 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -440,16 +440,16 @@ where t: &ty::Binder<'tcx, T>, ) -> ControlFlow { t.super_visit_with(self); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { match *r { // ignore bound regions, keep visiting - ty::ReLateBound(_, _) => ControlFlow::CONTINUE, + ty::ReLateBound(_, _) => ControlFlow::Continue(()), _ => { (self.op)(r); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -457,7 +457,7 @@ where fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { // We're only interested in types involving regions if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } match ty.kind() { @@ -507,7 +507,7 @@ where } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 8671f8d45a917..65b90aa3d79d3 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -147,7 +147,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeOrConstFinder<'a, 'tcx> { } else if !t.has_non_region_infer() { // All const/type variables in inference types must already be resolved, // no need to visit the contents. - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { // Otherwise, keep visiting. t.super_visit_with(self) @@ -178,7 +178,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeOrConstFinder<'a, 'tcx> { } else if !ct.has_non_region_infer() { // All const/type variables in inference types must already be resolved, // no need to visit the contents. - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { // Otherwise, keep visiting. ct.super_visit_with(self) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index f2ab44ac97c83..be47a3e238c1c 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1147,7 +1147,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { if !ty.has_opaque_types() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } if let ty::Alias(ty::Opaque, ..) = ty.kind() { diff --git a/compiler/rustc_macros/src/type_visitable.rs b/compiler/rustc_macros/src/type_visitable.rs index 14e6aa6e0c17b..1f95661ce9d5f 100644 --- a/compiler/rustc_macros/src/type_visitable.rs +++ b/compiler/rustc_macros/src/type_visitable.rs @@ -26,7 +26,7 @@ pub fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2: __visitor: &mut __V ) -> ::std::ops::ControlFlow<__V::BreakTy> { match *self { #body_visit } - ::std::ops::ControlFlow::CONTINUE + ::std::ops::ControlFlow::Continue(()) } }, ) diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index 5ca4d260179ce..250f3d0797eb5 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -93,7 +93,7 @@ macro_rules! TrivialTypeTraversalImpls { _: &mut F) -> ::std::ops::ControlFlow { - ::std::ops::ControlFlow::CONTINUE + ::std::ops::ControlFlow::Continue(()) } } )+ @@ -219,7 +219,7 @@ macro_rules! EnumTypeTraversalImpl { $($crate::ty::visit::TypeVisitable::visit_with( $variant_arg, $visitor )?;)* - ::std::ops::ControlFlow::CONTINUE + ::std::ops::ControlFlow::Continue(()) } $($output)* ) @@ -237,7 +237,7 @@ macro_rules! EnumTypeTraversalImpl { $($crate::ty::visit::TypeVisitable::visit_with( $variant_arg, $visitor )?;)* - ::std::ops::ControlFlow::CONTINUE + ::std::ops::ControlFlow::Continue(()) } $($output)* ) @@ -251,7 +251,7 @@ macro_rules! EnumTypeTraversalImpl { @VisitVariants($this, $visitor) input($($input)*) output( - $variant => { ::std::ops::ControlFlow::CONTINUE } + $variant => { ::std::ops::ControlFlow::Continue(()) } $($output)* ) ) diff --git a/compiler/rustc_middle/src/mir/type_visitable.rs b/compiler/rustc_middle/src/mir/type_visitable.rs index e7cd497b206a9..d44c6809bd830 100644 --- a/compiler/rustc_middle/src/mir/type_visitable.rs +++ b/compiler/rustc_middle/src/mir/type_visitable.rs @@ -4,6 +4,6 @@ use super::*; impl<'tcx, R: Idx, C: Idx> TypeVisitable<'tcx> for BitMatrix { fn visit_with>(&self, _: &mut V) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 42fc78a4715f4..a483945ccf262 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2481,7 +2481,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { if not_previously_inserted { ty.super_visit_with(self) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 81ec18684fd85..7d4d35b7fdf94 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -367,7 +367,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::AdtDef<'tcx> { impl<'tcx> TypeVisitable<'tcx> for ty::AdtDef<'tcx> { fn visit_with>(&self, _visitor: &mut V) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -714,7 +714,7 @@ impl<'tcx> TypeSuperVisitable<'tcx> for Ty<'tcx> { | ty::Placeholder(..) | ty::Param(..) | ty::Never - | ty::Foreign(..) => ControlFlow::CONTINUE, + | ty::Foreign(..) => ControlFlow::Continue(()), } } } @@ -742,7 +742,7 @@ impl<'tcx> TypeSuperFoldable<'tcx> for ty::Region<'tcx> { impl<'tcx> TypeSuperVisitable<'tcx> for ty::Region<'tcx> { fn super_visit_with>(&self, _visitor: &mut V) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -844,7 +844,7 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> { impl<'tcx> TypeVisitable<'tcx> for InferConst<'tcx> { fn visit_with>(&self, _visitor: &mut V) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 3f8252aefdc39..8720ee26b4273 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2015,7 +2015,7 @@ impl<'tcx> Ty<'tcx> { type BreakTy = (); fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { - if self.0 == t { ControlFlow::BREAK } else { t.super_visit_with(self) } + if self.0 == t { ControlFlow::Break(()) } else { t.super_visit_with(self) } } } diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index ca44555813138..bee3cc4d7cb9b 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -294,13 +294,13 @@ impl<'tcx> TyCtxt<'tcx> { fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { match *r { ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => { if (self.callback)(r) { - ControlFlow::BREAK + ControlFlow::Break(()) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -311,7 +311,7 @@ impl<'tcx> TyCtxt<'tcx> { if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) { ty.super_visit_with(self) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -394,7 +394,7 @@ impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> { if t.outer_exclusive_binder() < self.binder_index || !self.visited.insert((self.binder_index, t)) { - return ControlFlow::BREAK; + return ControlFlow::Break(()); } match *t.kind() { ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { @@ -512,7 +512,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { if t.outer_exclusive_binder() > self.outer_index { ControlFlow::Break(FoundEscapingVars) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -524,7 +524,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { if r.bound_at_or_above_binder(self.outer_index) { ControlFlow::Break(FoundEscapingVars) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -547,7 +547,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { if predicate.outer_exclusive_binder() > self.outer_index { ControlFlow::Break(FoundEscapingVars) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -575,7 +575,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -585,7 +585,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -596,7 +596,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -605,7 +605,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { if predicate.flags().intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -653,7 +653,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { // in the normalized form if self.just_constrained { if let ty::Alias(..) = t.kind() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } } @@ -666,7 +666,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { // in the normalized form if self.just_constrained { if let ty::ConstKind::Unevaluated(..) = c.kind() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } } @@ -679,7 +679,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { self.regions.insert(br.kind); } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -726,6 +726,6 @@ impl<'tcx> TypeVisitor<'tcx> for MaxUniverse { ); } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index fac4997fcbf6d..f67f24b43c4d7 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -118,7 +118,7 @@ impl<'mir, 'tcx> TriColorVisitor> for Search<'mir, 'tcx> { // A diverging InlineAsm is treated as non-recursing TerminatorKind::InlineAsm { destination, .. } => { if destination.is_some() { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { ControlFlow::Break(NonRecursive) } @@ -132,7 +132,7 @@ impl<'mir, 'tcx> TriColorVisitor> for Search<'mir, 'tcx> { | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::Goto { .. } - | TerminatorKind::SwitchInt { .. } => ControlFlow::CONTINUE, + | TerminatorKind::SwitchInt { .. } => ControlFlow::Continue(()), } } @@ -145,7 +145,7 @@ impl<'mir, 'tcx> TriColorVisitor> for Search<'mir, 'tcx> { } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool { diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index c8fc69eb856ab..cf13d4584a124 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -300,20 +300,20 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow { if !c.has_non_region_param() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } match c.kind() { ty::ConstKind::Param(param) => { debug!(?param); self.unused_parameters.mark_used(param.index); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) if matches!(self.tcx.def_kind(def.did), DefKind::AnonConst) => { self.visit_child_body(def.did, substs); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => c.super_visit_with(self), } @@ -322,7 +322,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { if !ty.has_non_region_param() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } match *ty.kind() { @@ -330,18 +330,18 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { debug!(?def_id); // Avoid cycle errors with generators. if def_id == self.def_id { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } // Consider any generic parameters used by any closures/generators as used in the // parent. self.visit_child_body(def_id, substs); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } ty::Param(param) => { debug!(?param); self.unused_parameters.mark_used(param.index); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => ty.super_visit_with(self), } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index fb55bb4afaac3..1c492c53de7e1 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -112,7 +112,11 @@ where fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow { let TraitRef { def_id, substs, .. } = trait_ref; self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path())?; - if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) } + if self.def_id_visitor.shallow() { + ControlFlow::Continue(()) + } else { + substs.visit_with(self) + } } fn visit_projection_ty(&mut self, projection: ty::AliasTy<'tcx>) -> ControlFlow { @@ -131,7 +135,7 @@ where }; self.visit_trait(trait_ref)?; if self.def_id_visitor.shallow() { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { assoc_substs.iter().try_for_each(|subst| subst.visit_with(self)) } @@ -155,7 +159,7 @@ where ty, _region, ))) => ty.visit_with(self), - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) => ControlFlow::CONTINUE, + ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) => ControlFlow::Continue(()), ty::PredicateKind::ConstEvaluatable(ct) => ct.visit_with(self), ty::PredicateKind::WellFormed(arg) => arg.visit_with(self), _ => bug!("unexpected predicate: {:?}", predicate), @@ -189,7 +193,7 @@ where | ty::Generator(def_id, ..) => { self.def_id_visitor.visit_def_id(def_id, "type", &ty)?; if self.def_id_visitor.shallow() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } // Default type visitor doesn't visit signatures of fn types. // Something like `fn() -> Priv {my_func}` is considered a private type even if @@ -214,7 +218,7 @@ where // as visible/reachable even if both `Type` and `Trait` are private. // Ideally, associated types should be substituted in the same way as // free type aliases, but this isn't done yet. - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } // This will also visit substs if necessary, so we don't need to recurse. return self.visit_projection_ty(proj); @@ -274,7 +278,7 @@ where } if self.def_id_visitor.shallow() { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { ty.super_visit_with(self) } @@ -319,7 +323,7 @@ impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL> if let Some(def_id) = def_id.as_local() { self.min = VL::new_min(self, def_id); } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -881,7 +885,7 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> self.ev.update(def_id, self.level); } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -1368,9 +1372,9 @@ impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> { descr: &dyn fmt::Display, ) -> ControlFlow { if self.check_def_id(def_id, kind, descr) { - ControlFlow::BREAK + ControlFlow::Break(()) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -1865,9 +1869,9 @@ impl<'tcx> DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> { descr: &dyn fmt::Display, ) -> ControlFlow { if self.check_def_id(def_id, kind, descr) { - ControlFlow::BREAK + ControlFlow::Break(()) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 0edae34190c30..5f649852d0bbd 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -614,12 +614,12 @@ impl<'tcx> OrphanChecker<'tcx> { fn found_non_local_ty(&mut self, t: Ty<'tcx>) -> ControlFlow> { self.non_local_tys.push((t, self.in_self_ty)); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn found_param_ty(&mut self, t: Ty<'tcx>) -> ControlFlow> { if self.search_first_local_ty { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(t)) } @@ -641,7 +641,7 @@ enum OrphanCheckEarlyExit<'tcx> { impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> { type BreakTy = OrphanCheckEarlyExit<'tcx>; fn visit_region(&mut self, _r: ty::Region<'tcx>) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { @@ -756,6 +756,6 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> { /// parameters, allowing uncovered const parameters in impls seems more useful /// than allowing `impl Trait for i32` to compile. fn visit_const(&mut self, _c: ty::Const<'tcx>) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 71fb6058cd2c5..f779d9dd8d935 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -198,7 +198,7 @@ fn satisfied_from_param_env<'tcx>( // If we start allowing directly writing `ConstKind::Expr` without an intermediate anon const // this will be incorrect. It might be worth investigating making `predicates_of` elaborate // all of the `ConstEvaluatable` bounds rather than having a visitor here. - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } 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 32b0f65176c18..434f75de02bff 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -2932,7 +2932,7 @@ impl<'tcx> ty::TypeVisitor<'tcx> for HasNumericInferVisitor { if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) { ControlFlow::Break(()) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 531aa23d6eac5..f036a311d464c 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -493,7 +493,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI && let param_def_id = self.generics.type_param(param, self.tcx).def_id && self.tcx.parent(param_def_id) == self.trait_item_def_id { - return ControlFlow::BREAK; + return ControlFlow::Break(()); } t.super_visit_with(self) } @@ -502,7 +502,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI && let param_def_id = self.generics.region_param(¶m, self.tcx).def_id && self.tcx.parent(param_def_id) == self.trait_item_def_id { - return ControlFlow::BREAK; + return ControlFlow::Break(()); } r.super_visit_with(self) } @@ -511,7 +511,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI && let param_def_id = self.generics.const_param(¶m, self.tcx).def_id && self.tcx.parent(param_def_id) == self.trait_item_def_id { - return ControlFlow::BREAK; + return ControlFlow::Break(()); } ct.super_visit_with(self) } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 9a0e3d298eda1..c9121212cd8f1 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -783,16 +783,16 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>( match t.kind() { ty::Param(_) => { if t == self.tcx.types.self_param { - ControlFlow::BREAK + ControlFlow::Break(()) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } ty::Alias(ty::Projection, ref data) if self.tcx.def_kind(data.def_id) == DefKind::ImplTraitPlaceholder => { // We'll deny these later in their own pass - ControlFlow::CONTINUE + ControlFlow::Continue(()) } ty::Alias(ty::Projection, ref data) => { // This is a projected type `::X`. @@ -820,7 +820,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>( .contains(&data.trait_ref(self.tcx).def_id); if is_supertrait_of_current_trait { - ControlFlow::CONTINUE // do not walk contained types, do not report error, do collect $200 + ControlFlow::Continue(()) // do not walk contained types, do not report error, do collect $200 } else { t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error } diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index c6ef13e185b2d..1531c50760d53 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -133,7 +133,7 @@ impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor { .escaping .max(t.outer_exclusive_binder().as_usize() - self.outer_index.as_usize()); } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } #[inline] @@ -145,7 +145,7 @@ impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor { } _ => {} } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow { @@ -153,7 +153,7 @@ impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor { ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => { self.escaping = self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize()); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => ct.super_visit_with(self), } diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index 892a7afd799c7..f398fb06c187a 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -107,25 +107,25 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { ty::FnDef(..) => { // Types of formals and return in `fn(_) -> _` are also irrelevant; // so we do not recur into them via `super_visit_with` - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } ty::Array(_, n) if { n.try_eval_usize(self.tcx, ty::ParamEnv::reveal_all()) == Some(0) } => { // rust-lang/rust#62336: ignore type of contents // for empty array. - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Str | ty::Never => { // These primitive types are always structural match. // // `Never` is kind of special here, but as it is not inhabitable, this should be fine. - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } ty::FnPtr(..) => { if !self.adt_const_param { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } else { return ControlFlow::Break(ty); } @@ -147,7 +147,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { // Even though `NonStructural` does not implement `PartialEq`, // structural equality on `T` does not recur into the raw // pointer. Therefore, one can still use `C` in a pattern. - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } else { return ControlFlow::Break(ty); } @@ -155,7 +155,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { ty::Float(_) => { if !self.adt_const_param { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } else { return ControlFlow::Break(ty); } @@ -172,13 +172,13 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { self.tcx.sess.delay_span_bug(self.span, "ty::Error in structural-match check"); // We still want to check other types after encountering an error, // as this may still emit relevant errors. - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } }; if !self.seen.insert(adt_def.did()) { debug!("Search already seen adt_def: {:?}", adt_def); - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } if !self.type_marked_structural(ty) { From 5a685a10ec9a8fb6d236f91ab11298c2cf0740c6 Mon Sep 17 00:00:00 2001 From: Albert Larsan Date: Wed, 18 Jan 2023 14:08:41 +0100 Subject: [PATCH 06/18] Correct typo --- compiler/rustc_trait_selection/src/solve/project_goals.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 0658836fb9cd3..a2aad049998af 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -23,7 +23,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { &mut self, goal: Goal<'tcx, ProjectionPredicate<'tcx>>, ) -> QueryResult<'tcx> { - // To only compute normalization ones for each projection we only + // To only compute normalization once for each projection we only // normalize if the expected term is an unconstrained inference variable. // // E.g. for `::Assoc = u32` we recursively compute the goal From b84b1da2dbacdfd7e33428540062380b56bfd8de Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 17 Jan 2023 19:29:52 +0000 Subject: [PATCH 07/18] Canonicalize trait solver response inside probe --- .../src/solve/assembly.rs | 22 +++++++------------ .../rustc_trait_selection/src/solve/mod.rs | 7 ++++++ .../src/solve/project_goals.rs | 10 ++++----- .../src/solve/trait_goals.rs | 10 ++++----- 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index cd6e4d2bccd5c..c8611294449e9 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -1,7 +1,7 @@ //! Code shared by trait and projection goals for candidate assembly. use super::infcx_ext::InferCtxtExt; -use super::{CanonicalResponse, Certainty, EvalCtxt, Goal}; +use super::{CanonicalResponse, EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::TypeFoldable; @@ -89,18 +89,18 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, impl_def_id: DefId, - ) -> Result; + ) -> QueryResult<'tcx>; fn consider_builtin_sized_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> Result; + ) -> QueryResult<'tcx>; fn consider_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, - ) -> Result; + ) -> QueryResult<'tcx>; } impl<'tcx> EvalCtxt<'_, 'tcx> { pub(super) fn assemble_and_evaluate_candidates>( @@ -180,9 +180,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { tcx.for_each_relevant_impl( goal.predicate.trait_def_id(tcx), goal.predicate.self_ty(), - |impl_def_id| match G::consider_impl_candidate(self, goal, impl_def_id) - .and_then(|certainty| self.make_canonical_response(certainty)) - { + |impl_def_id| match G::consider_impl_candidate(self, goal, impl_def_id) { Ok(result) => candidates .push(Candidate { source: CandidateSource::Impl(impl_def_id), result }), Err(NoSolution) => (), @@ -203,7 +201,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { Err(NoSolution) }; - match result.and_then(|certainty| self.make_canonical_response(certainty)) { + match result { Ok(result) => { candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result }) } @@ -217,9 +215,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { candidates: &mut Vec>, ) { for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() { - match G::consider_assumption(self, goal, assumption) - .and_then(|certainty| self.make_canonical_response(certainty)) - { + match G::consider_assumption(self, goal, assumption) { Ok(result) => { candidates.push(Candidate { source: CandidateSource::ParamEnv(i), result }) } @@ -268,9 +264,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { .subst_iter_copied(self.tcx(), alias_ty.substs) .enumerate() { - match G::consider_assumption(self, goal, assumption) - .and_then(|certainty| self.make_canonical_response(certainty)) - { + match G::consider_assumption(self, goal, assumption) { Ok(result) => { candidates.push(Candidate { source: CandidateSource::AliasBound(i), result }) } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 579cd6a2d59cd..32eb84635b536 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -313,6 +313,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } }) } + + fn evaluate_all_and_make_canonical_response( + &mut self, + goals: Vec>>, + ) -> QueryResult<'tcx> { + self.evaluate_all(goals).and_then(|certainty| self.make_canonical_response(certainty)) + } } #[instrument(level = "debug", skip(infcx), ret)] diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 0658836fb9cd3..1d85d31705ad4 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -191,7 +191,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, ProjectionPredicate<'tcx>>, impl_def_id: DefId, - ) -> Result { + ) -> QueryResult<'tcx> { let tcx = ecx.tcx(); let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx); @@ -229,7 +229,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { impl_def_id )? else { let certainty = Certainty::Maybe(MaybeCause::Ambiguity); - return Ok(trait_ref_certainty.unify_and(certainty)); + return ecx.make_canonical_response(trait_ref_certainty.unify_and(certainty)); }; if !assoc_def.item.defaultness(tcx).has_value() { @@ -286,14 +286,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { let rhs_certainty = ecx.evaluate_all(nested_goals).expect("failed to unify with unconstrained term"); - Ok(trait_ref_certainty.unify_and(rhs_certainty)) + ecx.make_canonical_response(trait_ref_certainty.unify_and(rhs_certainty)) }) } fn consider_builtin_sized_candidate( _ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> Result { + ) -> QueryResult<'tcx> { bug!("`Sized` does not have an associated type: {:?}", goal); } @@ -301,7 +301,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { _ecx: &mut EvalCtxt<'_, 'tcx>, _goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, - ) -> Result { + ) -> QueryResult<'tcx> { if let Some(_poly_projection_pred) = assumption.to_opt_poly_projection_pred() { unimplemented!() } else { diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index bbe175d5cc853..111758c77d99c 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -4,7 +4,7 @@ use std::iter; use super::assembly::{self, Candidate, CandidateSource}; use super::infcx_ext::InferCtxtExt; -use super::{Certainty, EvalCtxt, Goal, QueryResult}; +use super::{EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; @@ -29,7 +29,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, TraitPredicate<'tcx>>, impl_def_id: DefId, - ) -> Result { + ) -> QueryResult<'tcx> { let tcx = ecx.tcx(); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); @@ -53,14 +53,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { .into_iter() .map(|pred| goal.with(tcx, pred)); nested_goals.extend(where_clause_bounds); - ecx.evaluate_all(nested_goals) + ecx.evaluate_all_and_make_canonical_response(nested_goals) }) } fn consider_builtin_sized_candidate( _ecx: &mut EvalCtxt<'_, 'tcx>, _goal: Goal<'tcx, Self>, - ) -> Result { + ) -> QueryResult<'tcx> { unimplemented!(); } @@ -68,7 +68,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { _ecx: &mut EvalCtxt<'_, 'tcx>, _goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, - ) -> Result { + ) -> QueryResult<'tcx> { if let Some(_poly_trait_pred) = assumption.to_opt_poly_trait_pred() { unimplemented!() } else { From f99b273d577914ee0c9073e2e6144aee17354717 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 17 Jan 2023 19:50:50 +0000 Subject: [PATCH 08/18] implement consider_assumption --- .../src/solve/infcx_ext.rs | 26 ++++++++++++++ .../src/solve/project_goals.rs | 35 ++++++++++++++++--- .../src/solve/trait_goals.rs | 19 +++++++--- 3 files changed, 70 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs index 9b7feb5053787..47e6c93016a0e 100644 --- a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs +++ b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs @@ -25,6 +25,13 @@ pub(super) trait InferCtxtExt<'tcx> { lhs: T, rhs: T, ) -> Result>>, NoSolution>; + + fn sup>( + &self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + rhs: T, + ) -> Result>>, NoSolution>; } impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { @@ -59,4 +66,23 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { NoSolution }) } + + #[instrument(level = "debug", skip(self, param_env), ret)] + fn sup>( + &self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + rhs: T, + ) -> Result>>, NoSolution> { + self.at(&ObligationCause::dummy(), param_env) + .define_opaque_types(false) + .sup(lhs, rhs) + .map(|InferOk { value: (), obligations }| { + obligations.into_iter().map(|o| o.into()).collect() + }) + .map_err(|e| { + debug!(?e, "failed to sup"); + NoSolution + }) + } } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 1d85d31705ad4..9ebcb4e4657d8 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -6,7 +6,7 @@ use super::{Certainty, EvalCtxt, Goal, MaybeCause, QueryResult}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; -use rustc_infer::infer::InferCtxt; +use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime}; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::specialization_graph::LeafDef; use rustc_infer::traits::Reveal; @@ -298,12 +298,37 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { } fn consider_assumption( - _ecx: &mut EvalCtxt<'_, 'tcx>, - _goal: Goal<'tcx, Self>, + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, ) -> QueryResult<'tcx> { - if let Some(_poly_projection_pred) = assumption.to_opt_poly_projection_pred() { - unimplemented!() + if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() { + ecx.infcx.probe(|_| { + let assumption_projection_pred = ecx.infcx.replace_bound_vars_with_fresh_vars( + DUMMY_SP, + LateBoundRegionConversionTime::HigherRankedType, + poly_projection_pred, + ); + let nested_goals = ecx.infcx.sup( + goal.param_env, + goal.predicate.projection_ty, + assumption_projection_pred.projection_ty, + )?; + let subst_certainty = ecx.evaluate_all(nested_goals)?; + + // The term of our goal should be fully unconstrained, so this should never fail. + // + // It can however be ambiguous when the resolved type is a projection. + let nested_goals = ecx + .infcx + .eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term) + .expect("failed to unify with unconstrained term"); + let rhs_certainty = ecx + .evaluate_all(nested_goals) + .expect("failed to unify with unconstrained term"); + + ecx.make_canonical_response(subst_certainty.unify_and(rhs_certainty)) + }) } else { Err(NoSolution) } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 111758c77d99c..362424b0d1431 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -6,10 +6,11 @@ use super::assembly::{self, Candidate, CandidateSource}; use super::infcx_ext::InferCtxtExt; use super::{EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; +use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; -use rustc_middle::ty::TraitPredicate; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{ToPolyTraitRef, TraitPredicate}; use rustc_span::DUMMY_SP; impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { @@ -65,12 +66,20 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_assumption( - _ecx: &mut EvalCtxt<'_, 'tcx>, - _goal: Goal<'tcx, Self>, + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, ) -> QueryResult<'tcx> { - if let Some(_poly_trait_pred) = assumption.to_opt_poly_trait_pred() { - unimplemented!() + if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() { + // FIXME: Constness and polarity + ecx.infcx.probe(|_| { + let nested_goals = ecx.infcx.sup( + goal.param_env, + ty::Binder::dummy(goal.predicate.trait_ref), + poly_trait_pred.to_poly_trait_ref(), + )?; + ecx.evaluate_all_and_make_canonical_response(nested_goals) + }) } else { Err(NoSolution) } From 3d87a8e84850e2f5edc0f87ab2f4d3c2b67a48ac Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 17 Jan 2023 18:19:11 +0000 Subject: [PATCH 09/18] Assemble object bound candidates --- .../src/solve/assembly.rs | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index c8611294449e9..0a82c14e226fd 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -4,6 +4,7 @@ use super::infcx_ext::InferCtxtExt; use super::{CanonicalResponse, EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; +use rustc_infer::traits::util::elaborate_predicates; use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; use std::fmt::Debug; @@ -119,6 +120,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.assemble_alias_bound_candidates(goal, &mut candidates); + self.assemble_object_bound_candidates(goal, &mut candidates); + candidates } @@ -272,4 +275,53 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } } + + fn assemble_object_bound_candidates>( + &mut self, + goal: Goal<'tcx, G>, + candidates: &mut Vec>, + ) { + let self_ty = goal.predicate.self_ty(); + let bounds = match *self_ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_) + | ty::Alias(..) + | ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(_) + | ty::Never + | ty::Tuple(_) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Infer(_) + | ty::Error(_) => return, + ty::Bound(..) => bug!("unexpected bound type: {goal:?}"), + ty::Dynamic(bounds, ..) => bounds, + }; + + let tcx = self.tcx(); + for assumption in + elaborate_predicates(tcx, bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty))) + { + match G::consider_assumption(self, goal, assumption.predicate) + { + Ok(result) => { + candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result }) + } + Err(NoSolution) => (), + } + } + } } From 45aa5c0f90124e926662f2c2c2d9efca065e0397 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 17 Jan 2023 20:16:30 +0000 Subject: [PATCH 10/18] Auto and alias traits --- compiler/rustc_middle/src/ty/mod.rs | 5 + .../src/solve/assembly.rs | 25 +++- .../src/solve/project_goals.rs | 28 +++- .../src/solve/trait_goals.rs | 132 ++++++++++++++++-- 4 files changed, 169 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e68f27cc0fd5d..db7dd2e5e75d7 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2382,6 +2382,11 @@ impl<'tcx> TyCtxt<'tcx> { self.trait_def(trait_def_id).has_auto_impl } + /// Returns `true` if this is a trait alias. + pub fn trait_is_alias(self, trait_def_id: DefId) -> bool { + self.def_kind(trait_def_id) == DefKind::TraitAlias + } + pub fn trait_is_coinductive(self, trait_def_id: DefId) -> bool { self.trait_is_auto(trait_def_id) || self.lang_items().sized_trait() == Some(trait_def_id) } diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index 0a82c14e226fd..0759c42338249 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -92,15 +92,25 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy { impl_def_id: DefId, ) -> QueryResult<'tcx>; - fn consider_builtin_sized_candidate( + fn consider_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, + assumption: ty::Predicate<'tcx>, ) -> QueryResult<'tcx>; - fn consider_assumption( + fn consider_auto_trait_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx>; + + fn consider_trait_alias_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx>; + + fn consider_builtin_sized_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - assumption: ty::Predicate<'tcx>, ) -> QueryResult<'tcx>; } impl<'tcx> EvalCtxt<'_, 'tcx> { @@ -198,7 +208,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ) { let lang_items = self.tcx().lang_items(); let trait_def_id = goal.predicate.trait_def_id(self.tcx()); - let result = if lang_items.sized_trait() == Some(trait_def_id) { + let result = if self.tcx().trait_is_auto(trait_def_id) { + G::consider_auto_trait_candidate(self, goal) + } else if self.tcx().trait_is_alias(trait_def_id) { + G::consider_trait_alias_candidate(self, goal) + } else if lang_items.sized_trait() == Some(trait_def_id) { G::consider_builtin_sized_candidate(self, goal) } else { Err(NoSolution) @@ -315,8 +329,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { for assumption in elaborate_predicates(tcx, bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty))) { - match G::consider_assumption(self, goal, assumption.predicate) - { + match G::consider_assumption(self, goal, assumption.predicate) { Ok(result) => { candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result }) } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 9ebcb4e4657d8..3c74de09802d5 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -290,13 +290,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { }) } - fn consider_builtin_sized_candidate( - _ecx: &mut EvalCtxt<'_, 'tcx>, - goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { - bug!("`Sized` does not have an associated type: {:?}", goal); - } - fn consider_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, @@ -333,6 +326,27 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { Err(NoSolution) } } + + fn consider_auto_trait_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + bug!("auto traits do not have associated types: {:?}", goal); + } + + fn consider_trait_alias_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + bug!("trait aliases do not have associated types: {:?}", goal); + } + + fn consider_builtin_sized_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + bug!("`Sized` does not have an associated type: {:?}", goal); + } } /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code. diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 362424b0d1431..1f18de2e7a9e0 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -6,7 +6,7 @@ use super::assembly::{self, Candidate, CandidateSource}; use super::infcx_ext::InferCtxtExt; use super::{EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; -use rustc_infer::infer::LateBoundRegionConversionTime; +use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -58,13 +58,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { }) } - fn consider_builtin_sized_candidate( - _ecx: &mut EvalCtxt<'_, 'tcx>, - _goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { - unimplemented!(); - } - fn consider_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, @@ -84,9 +77,61 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { Err(NoSolution) } } + + fn consider_auto_trait_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + ecx.infcx.probe(|_| { + let constituent_tys = + instantiate_constituent_tys_for_auto_trait(ecx.infcx, goal.predicate.self_ty())?; + ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys) + }) + } + + fn consider_trait_alias_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + let tcx = ecx.tcx(); + + ecx.infcx.probe(|_| { + let nested_obligations = tcx + .predicates_of(goal.predicate.def_id()) + .instantiate(tcx, goal.predicate.trait_ref.substs); + ecx.evaluate_all_and_make_canonical_response( + nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)).collect(), + ) + }) + } + + fn consider_builtin_sized_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + _goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + unimplemented!(); + } } impl<'tcx> EvalCtxt<'_, 'tcx> { + fn evaluate_goal_for_constituent_tys_and_make_canonical_response( + &mut self, + goal: Goal<'tcx, TraitPredicate<'tcx>>, + constituent_tys: Vec>, + ) -> QueryResult<'tcx> { + self.evaluate_all_and_make_canonical_response( + constituent_tys + .into_iter() + .map(|ty| { + goal.with( + self.tcx(), + ty::Binder::dummy(goal.predicate.with_self_ty(self.tcx(), ty)), + ) + }) + .collect(), + ) + } + pub(super) fn compute_trait_goal( &mut self, goal: Goal<'tcx, TraitPredicate<'tcx>>, @@ -162,3 +207,74 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { candidate } } + +// Calculates the constituent types of a type for `auto trait` purposes. +// +// For types with an "existential" binder, i.e. generator witnesses, we also +// instantiate the binder with placeholders eagerly. +fn instantiate_constituent_tys_for_auto_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Result>, NoSolution> { + let tcx = infcx.tcx; + match *ty.kind() { + ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Str + | ty::Error(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Never + | ty::Char => Ok(vec![]), + + ty::Placeholder(..) + | ty::Dynamic(..) + | ty::Param(..) + | ty::Foreign(..) + | ty::Alias(ty::Projection, ..) + | ty::Bound(..) + | ty::Infer(ty::TyVar(_)) => { + // FIXME: Do we need to mark anything as ambiguous here? Yeah? + Err(NoSolution) + } + + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + + ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { + Ok(vec![element_ty]) + } + + ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]), + + ty::Tuple(ref tys) => { + // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet + Ok(tys.iter().collect()) + } + + ty::Closure(_, ref substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]), + + ty::Generator(_, ref substs, _) => { + let generator_substs = substs.as_generator(); + Ok(vec![generator_substs.tupled_upvars_ty(), generator_substs.witness()]) + } + + ty::GeneratorWitness(types) => { + Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) + } + + // For `PhantomData`, we pass `T`. + ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]), + + ty::Adt(def, substs) => Ok(def.all_fields().map(|f| f.ty(tcx, substs)).collect()), + + ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { + // We can resolve the `impl Trait` to its concrete type, + // which enforces a DAG between the functions requiring + // the auto trait bounds in question. + Ok(vec![tcx.bound_type_of(def_id).subst(tcx, substs)]) + } + } +} From 685c32fd858acf107108abd6d35782532a0064e2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 17 Jan 2023 20:24:58 +0000 Subject: [PATCH 11/18] Sized, Copy/Clone --- .../src/solve/assembly.rs | 10 ++ .../src/solve/project_goals.rs | 7 + .../src/solve/trait_goals.rs | 137 +++++++++++++++++- 3 files changed, 151 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index 0759c42338249..2336fb53aec28 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -112,7 +112,13 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + + fn consider_builtin_copy_clone_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx>; } + impl<'tcx> EvalCtxt<'_, 'tcx> { pub(super) fn assemble_and_evaluate_candidates>( &mut self, @@ -214,6 +220,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { G::consider_trait_alias_candidate(self, goal) } else if lang_items.sized_trait() == Some(trait_def_id) { G::consider_builtin_sized_candidate(self, goal) + } else if lang_items.copy_trait() == Some(trait_def_id) + || lang_items.clone_trait() == Some(trait_def_id) + { + G::consider_builtin_copy_clone_candidate(self, goal) } else { Err(NoSolution) }; diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 3c74de09802d5..5c1f3f02e93a8 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -347,6 +347,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ) -> QueryResult<'tcx> { bug!("`Sized` does not have an associated type: {:?}", goal); } + + fn consider_builtin_copy_clone_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal); + } } /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code. diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 1f18de2e7a9e0..4d94265dc07f5 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -6,6 +6,7 @@ use super::assembly::{self, Candidate, CandidateSource}; use super::infcx_ext::InferCtxtExt; use super::{EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; +use rustc_hir::{Movability, Mutability}; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; @@ -106,10 +107,27 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_sized_candidate( - _ecx: &mut EvalCtxt<'_, 'tcx>, - _goal: Goal<'tcx, Self>, + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { - unimplemented!(); + ecx.infcx.probe(|_| { + let constituent_tys = + instantiate_constituent_tys_for_sized_trait(ecx.infcx, goal.predicate.self_ty())?; + ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys) + }) + } + + fn consider_builtin_copy_clone_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + ecx.infcx.probe(|_| { + let constituent_tys = instantiate_constituent_tys_for_copy_clone_trait( + ecx.infcx, + goal.predicate.self_ty(), + )?; + ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys) + }) } } @@ -278,3 +296,116 @@ fn instantiate_constituent_tys_for_auto_trait<'tcx>( } } } + +fn instantiate_constituent_tys_for_sized_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Result>, NoSolution> { + match *ty.kind() { + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::RawPtr(..) + | ty::Char + | ty::Ref(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Array(..) + | ty::Closure(..) + | ty::Never + | ty::Dynamic(_, _, ty::DynStar) + | ty::Error(_) => Ok(vec![]), + + ty::Str + | ty::Slice(_) + | ty::Dynamic(..) + | ty::Foreign(..) + | ty::Alias(..) + | ty::Param(_) => Err(NoSolution), + + ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), + + ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + + ty::Tuple(tys) => Ok(tys.to_vec()), + + ty::Adt(def, substs) => { + let sized_crit = def.sized_constraint(infcx.tcx); + Ok(sized_crit + .0 + .iter() + .map(|ty| sized_crit.rebind(*ty).subst(infcx.tcx, substs)) + .collect()) + } + } +} + +fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Result>, NoSolution> { + match *ty.kind() { + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Error(_) => Ok(vec![]), + + // Implementations are provided in core + ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Ref(_, _, Mutability::Not) + | ty::Array(..) => Err(NoSolution), + + ty::Dynamic(..) + | ty::Str + | ty::Slice(_) + | ty::Generator(_, _, Movability::Static) + | ty::Foreign(..) + | ty::Ref(_, _, Mutability::Mut) + | ty::Adt(_, _) + | ty::Alias(_, _) + | ty::Param(_) => Err(NoSolution), + + ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), + + ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + + ty::Tuple(tys) => Ok(tys.to_vec()), + + ty::Closure(_, substs) => match *substs.as_closure().tupled_upvars_ty().kind() { + ty::Tuple(tys) => Ok(tys.to_vec()), + ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), + _ => bug!(), + }, + + ty::Generator(_, substs, Movability::Movable) => { + if infcx.tcx.features().generator_clone { + let generator = substs.as_generator(); + match *generator.tupled_upvars_ty().kind() { + ty::Tuple(tys) => Ok(tys.iter().chain([generator.witness()]).collect()), + ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), + _ => bug!(), + } + } else { + Err(NoSolution) + } + } + + ty::GeneratorWitness(types) => { + Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) + } + } +} From 34127c50803cc0a3c68f1f15480399e19d3813af Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 18 Jan 2023 14:40:16 +0000 Subject: [PATCH 12/18] no subtyping in the new trait solver --- .../src/solve/infcx_ext.rs | 36 +++++++------------ .../src/solve/project_goals.rs | 11 +++--- .../src/solve/trait_goals.rs | 10 +++--- 3 files changed, 23 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs index 47e6c93016a0e..42f597c781d25 100644 --- a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs +++ b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs @@ -1,10 +1,10 @@ use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::{InferCtxt, InferOk}; +use rustc_infer::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::ObligationCause; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TypeFoldable}; use rustc_span::DUMMY_SP; use super::Goal; @@ -26,12 +26,10 @@ pub(super) trait InferCtxtExt<'tcx> { rhs: T, ) -> Result>>, NoSolution>; - fn sup>( + fn instantiate_bound_vars_with_infer + Copy>( &self, - param_env: ty::ParamEnv<'tcx>, - lhs: T, - rhs: T, - ) -> Result>>, NoSolution>; + value: ty::Binder<'tcx, T>, + ) -> T; } impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { @@ -67,22 +65,14 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { }) } - #[instrument(level = "debug", skip(self, param_env), ret)] - fn sup>( + fn instantiate_bound_vars_with_infer + Copy>( &self, - param_env: ty::ParamEnv<'tcx>, - lhs: T, - rhs: T, - ) -> Result>>, NoSolution> { - self.at(&ObligationCause::dummy(), param_env) - .define_opaque_types(false) - .sup(lhs, rhs) - .map(|InferOk { value: (), obligations }| { - obligations.into_iter().map(|o| o.into()).collect() - }) - .map_err(|e| { - debug!(?e, "failed to sup"); - NoSolution - }) + value: ty::Binder<'tcx, T>, + ) -> T { + self.replace_bound_vars_with_fresh_vars( + DUMMY_SP, + LateBoundRegionConversionTime::HigherRankedType, + value, + ) } } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 5c1f3f02e93a8..00c7edf0ef8a3 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -6,7 +6,7 @@ use super::{Certainty, EvalCtxt, Goal, MaybeCause, QueryResult}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; -use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime}; +use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::specialization_graph::LeafDef; use rustc_infer::traits::Reveal; @@ -297,12 +297,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ) -> QueryResult<'tcx> { if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() { ecx.infcx.probe(|_| { - let assumption_projection_pred = ecx.infcx.replace_bound_vars_with_fresh_vars( - DUMMY_SP, - LateBoundRegionConversionTime::HigherRankedType, - poly_projection_pred, - ); - let nested_goals = ecx.infcx.sup( + let assumption_projection_pred = + ecx.infcx.instantiate_bound_vars_with_infer(poly_projection_pred); + let nested_goals = ecx.infcx.eq( goal.param_env, goal.predicate.projection_ty, assumption_projection_pred.projection_ty, diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 4d94265dc07f5..d89759f4dd487 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -10,8 +10,8 @@ use rustc_hir::{Movability, Mutability}; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; +use rustc_middle::ty::TraitPredicate; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_middle::ty::{ToPolyTraitRef, TraitPredicate}; use rustc_span::DUMMY_SP; impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { @@ -67,10 +67,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() { // FIXME: Constness and polarity ecx.infcx.probe(|_| { - let nested_goals = ecx.infcx.sup( + let assumption_trait_pred = + ecx.infcx.instantiate_bound_vars_with_infer(poly_trait_pred); + let nested_goals = ecx.infcx.eq( goal.param_env, - ty::Binder::dummy(goal.predicate.trait_ref), - poly_trait_pred.to_poly_trait_ref(), + goal.predicate.trait_ref, + assumption_trait_pred.trait_ref, )?; ecx.evaluate_all_and_make_canonical_response(nested_goals) }) From f672436f04938da11c74664f6665f28018f0a390 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 18 Jan 2023 14:56:44 +0000 Subject: [PATCH 13/18] Handle structural traits more gracefully --- .../src/solve/trait_goals.rs | 248 +++--------------- .../solve/trait_goals/structural_traits.rs | 179 +++++++++++++ 2 files changed, 212 insertions(+), 215 deletions(-) create mode 100644 compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index d89759f4dd487..1ebcfd03c14ea 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -6,7 +6,6 @@ use super::assembly::{self, Candidate, CandidateSource}; use super::infcx_ext::InferCtxtExt; use super::{EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; -use rustc_hir::{Movability, Mutability}; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; @@ -14,6 +13,8 @@ use rustc_middle::ty::TraitPredicate; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::DUMMY_SP; +mod structural_traits; + impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn self_ty(self) -> Ty<'tcx> { self.self_ty() @@ -85,11 +86,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { - ecx.infcx.probe(|_| { - let constituent_tys = - instantiate_constituent_tys_for_auto_trait(ecx.infcx, goal.predicate.self_ty())?; - ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys) - }) + ecx.probe_and_evaluate_goal_for_constituent_tys( + goal, + structural_traits::instantiate_constituent_tys_for_auto_trait, + ) } fn consider_trait_alias_candidate( @@ -112,44 +112,46 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { - ecx.infcx.probe(|_| { - let constituent_tys = - instantiate_constituent_tys_for_sized_trait(ecx.infcx, goal.predicate.self_ty())?; - ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys) - }) + ecx.probe_and_evaluate_goal_for_constituent_tys( + goal, + structural_traits::instantiate_constituent_tys_for_sized_trait, + ) } fn consider_builtin_copy_clone_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { - ecx.infcx.probe(|_| { - let constituent_tys = instantiate_constituent_tys_for_copy_clone_trait( - ecx.infcx, - goal.predicate.self_ty(), - )?; - ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys) - }) + ecx.probe_and_evaluate_goal_for_constituent_tys( + goal, + structural_traits::instantiate_constituent_tys_for_copy_clone_trait, + ) } } impl<'tcx> EvalCtxt<'_, 'tcx> { - fn evaluate_goal_for_constituent_tys_and_make_canonical_response( + /// Convenience function for traits that are structural, i.e. that only + /// have nested subgoals that only change the self type. Unlike other + /// evaluate-like helpers, this does a probe, so it doesn't need to be + /// wrapped in one. + fn probe_and_evaluate_goal_for_constituent_tys( &mut self, goal: Goal<'tcx, TraitPredicate<'tcx>>, - constituent_tys: Vec>, + constituent_tys: impl Fn(&InferCtxt<'tcx>, Ty<'tcx>) -> Result>, NoSolution>, ) -> QueryResult<'tcx> { - self.evaluate_all_and_make_canonical_response( - constituent_tys - .into_iter() - .map(|ty| { - goal.with( - self.tcx(), - ty::Binder::dummy(goal.predicate.with_self_ty(self.tcx(), ty)), - ) - }) - .collect(), - ) + self.infcx.probe(|_| { + self.evaluate_all_and_make_canonical_response( + constituent_tys(self.infcx, goal.predicate.self_ty())? + .into_iter() + .map(|ty| { + goal.with( + self.tcx(), + ty::Binder::dummy(goal.predicate.with_self_ty(self.tcx(), ty)), + ) + }) + .collect(), + ) + }) } pub(super) fn compute_trait_goal( @@ -227,187 +229,3 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { candidate } } - -// Calculates the constituent types of a type for `auto trait` purposes. -// -// For types with an "existential" binder, i.e. generator witnesses, we also -// instantiate the binder with placeholders eagerly. -fn instantiate_constituent_tys_for_auto_trait<'tcx>( - infcx: &InferCtxt<'tcx>, - ty: Ty<'tcx>, -) -> Result>, NoSolution> { - let tcx = infcx.tcx; - match *ty.kind() { - ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Float(_) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Str - | ty::Error(_) - | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) - | ty::Never - | ty::Char => Ok(vec![]), - - ty::Placeholder(..) - | ty::Dynamic(..) - | ty::Param(..) - | ty::Foreign(..) - | ty::Alias(ty::Projection, ..) - | ty::Bound(..) - | ty::Infer(ty::TyVar(_)) => { - // FIXME: Do we need to mark anything as ambiguous here? Yeah? - Err(NoSolution) - } - - ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), - - ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { - Ok(vec![element_ty]) - } - - ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]), - - ty::Tuple(ref tys) => { - // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - Ok(tys.iter().collect()) - } - - ty::Closure(_, ref substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]), - - ty::Generator(_, ref substs, _) => { - let generator_substs = substs.as_generator(); - Ok(vec![generator_substs.tupled_upvars_ty(), generator_substs.witness()]) - } - - ty::GeneratorWitness(types) => { - Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) - } - - // For `PhantomData`, we pass `T`. - ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]), - - ty::Adt(def, substs) => Ok(def.all_fields().map(|f| f.ty(tcx, substs)).collect()), - - ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { - // We can resolve the `impl Trait` to its concrete type, - // which enforces a DAG between the functions requiring - // the auto trait bounds in question. - Ok(vec![tcx.bound_type_of(def_id).subst(tcx, substs)]) - } - } -} - -fn instantiate_constituent_tys_for_sized_trait<'tcx>( - infcx: &InferCtxt<'tcx>, - ty: Ty<'tcx>, -) -> Result>, NoSolution> { - match *ty.kind() { - ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) - | ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Float(_) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::RawPtr(..) - | ty::Char - | ty::Ref(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) - | ty::Array(..) - | ty::Closure(..) - | ty::Never - | ty::Dynamic(_, _, ty::DynStar) - | ty::Error(_) => Ok(vec![]), - - ty::Str - | ty::Slice(_) - | ty::Dynamic(..) - | ty::Foreign(..) - | ty::Alias(..) - | ty::Param(_) => Err(NoSolution), - - ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), - - ty::Placeholder(..) - | ty::Bound(..) - | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), - - ty::Tuple(tys) => Ok(tys.to_vec()), - - ty::Adt(def, substs) => { - let sized_crit = def.sized_constraint(infcx.tcx); - Ok(sized_crit - .0 - .iter() - .map(|ty| sized_crit.rebind(*ty).subst(infcx.tcx, substs)) - .collect()) - } - } -} - -fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( - infcx: &InferCtxt<'tcx>, - ty: Ty<'tcx>, -) -> Result>, NoSolution> { - match *ty.kind() { - ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Error(_) => Ok(vec![]), - - // Implementations are provided in core - ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Float(_) - | ty::Char - | ty::RawPtr(..) - | ty::Never - | ty::Ref(_, _, Mutability::Not) - | ty::Array(..) => Err(NoSolution), - - ty::Dynamic(..) - | ty::Str - | ty::Slice(_) - | ty::Generator(_, _, Movability::Static) - | ty::Foreign(..) - | ty::Ref(_, _, Mutability::Mut) - | ty::Adt(_, _) - | ty::Alias(_, _) - | ty::Param(_) => Err(NoSolution), - - ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), - - ty::Placeholder(..) - | ty::Bound(..) - | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), - - ty::Tuple(tys) => Ok(tys.to_vec()), - - ty::Closure(_, substs) => match *substs.as_closure().tupled_upvars_ty().kind() { - ty::Tuple(tys) => Ok(tys.to_vec()), - ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), - _ => bug!(), - }, - - ty::Generator(_, substs, Movability::Movable) => { - if infcx.tcx.features().generator_clone { - let generator = substs.as_generator(); - match *generator.tupled_upvars_ty().kind() { - ty::Tuple(tys) => Ok(tys.iter().chain([generator.witness()]).collect()), - ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), - _ => bug!(), - } - } else { - Err(NoSolution) - } - } - - ty::GeneratorWitness(types) => { - Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) - } - } -} diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs new file mode 100644 index 0000000000000..bbc0c77253278 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs @@ -0,0 +1,179 @@ +use rustc_hir::{Movability, Mutability}; +use rustc_infer::{infer::InferCtxt, traits::query::NoSolution}; +use rustc_middle::ty::{self, Ty}; + +// Calculates the constituent types of a type for `auto trait` purposes. +// +// For types with an "existential" binder, i.e. generator witnesses, we also +// instantiate the binder with placeholders eagerly. +pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Result>, NoSolution> { + let tcx = infcx.tcx; + match *ty.kind() { + ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Str + | ty::Error(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Never + | ty::Char => Ok(vec![]), + + ty::Placeholder(..) + | ty::Dynamic(..) + | ty::Param(..) + | ty::Foreign(..) + | ty::Alias(ty::Projection, ..) + | ty::Bound(..) + | ty::Infer(ty::TyVar(_)) => { + // FIXME: Do we need to mark anything as ambiguous here? Yeah? + Err(NoSolution) + } + + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + + ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { + Ok(vec![element_ty]) + } + + ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]), + + ty::Tuple(ref tys) => { + // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet + Ok(tys.iter().collect()) + } + + ty::Closure(_, ref substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]), + + ty::Generator(_, ref substs, _) => { + let generator_substs = substs.as_generator(); + Ok(vec![generator_substs.tupled_upvars_ty(), generator_substs.witness()]) + } + + ty::GeneratorWitness(types) => { + Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) + } + + // For `PhantomData`, we pass `T`. + ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]), + + ty::Adt(def, substs) => Ok(def.all_fields().map(|f| f.ty(tcx, substs)).collect()), + + ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { + // We can resolve the `impl Trait` to its concrete type, + // which enforces a DAG between the functions requiring + // the auto trait bounds in question. + Ok(vec![tcx.bound_type_of(def_id).subst(tcx, substs)]) + } + } +} + +pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Result>, NoSolution> { + match *ty.kind() { + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::RawPtr(..) + | ty::Char + | ty::Ref(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Array(..) + | ty::Closure(..) + | ty::Never + | ty::Dynamic(_, _, ty::DynStar) + | ty::Error(_) => Ok(vec![]), + + ty::Str + | ty::Slice(_) + | ty::Dynamic(..) + | ty::Foreign(..) + | ty::Alias(..) + | ty::Param(_) => Err(NoSolution), + + ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), + + ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + + ty::Tuple(tys) => Ok(tys.to_vec()), + + ty::Adt(def, substs) => { + let sized_crit = def.sized_constraint(infcx.tcx); + Ok(sized_crit + .0 + .iter() + .map(|ty| sized_crit.rebind(*ty).subst(infcx.tcx, substs)) + .collect()) + } + } +} + +pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Result>, NoSolution> { + match *ty.kind() { + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Error(_) => Ok(vec![]), + + // Implementations are provided in core + ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Ref(_, _, Mutability::Not) + | ty::Array(..) => Err(NoSolution), + + ty::Dynamic(..) + | ty::Str + | ty::Slice(_) + | ty::Generator(_, _, Movability::Static) + | ty::Foreign(..) + | ty::Ref(_, _, Mutability::Mut) + | ty::Adt(_, _) + | ty::Alias(_, _) + | ty::Param(_) => Err(NoSolution), + + ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), + + ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + + ty::Tuple(tys) => Ok(tys.to_vec()), + + ty::Closure(_, substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]), + + ty::Generator(_, substs, Movability::Movable) => { + if infcx.tcx.features().generator_clone { + let generator = substs.as_generator(); + Ok(vec![generator.tupled_upvars_ty(), generator.witness()]) + } else { + Err(NoSolution) + } + } + + ty::GeneratorWitness(types) => { + Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) + } + } +} From 7d57685682778900cb3b8d57605a143d402b8d0c Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 18 Jan 2023 10:22:21 -0800 Subject: [PATCH 14/18] Also remove `#![feature(control_flow_enum)]` where possible --- compiler/rustc_const_eval/src/lib.rs | 1 - compiler/rustc_data_structures/src/lib.rs | 1 - compiler/rustc_mir_build/src/lib.rs | 1 - compiler/rustc_monomorphize/src/lib.rs | 1 - compiler/rustc_privacy/src/lib.rs | 1 - compiler/rustc_transmute/src/lib.rs | 2 +- compiler/rustc_ty_utils/src/lib.rs | 1 - 7 files changed, 1 insertion(+), 7 deletions(-) diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 46e7b09a55e10..57b91df2d0708 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -6,7 +6,6 @@ Rust MIR: a lowered representation of Rust. #![feature(assert_matches)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(decl_macro)] #![feature(exact_size_is_empty)] #![feature(let_chains)] diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 3a2000233c5d1..954e84c303b83 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -11,7 +11,6 @@ #![feature(associated_type_bounds)] #![feature(auto_traits)] #![feature(cell_leak)] -#![feature(control_flow_enum)] #![feature(extend_one)] #![feature(hash_raw_entry)] #![feature(hasher_prefixfree_extras)] diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index fb7ae6f1d2424..a428180a4fa82 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -5,7 +5,6 @@ #![feature(assert_matches)] #![feature(associated_type_bounds)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(if_let_guard)] #![feature(let_chains)] #![feature(min_specialization)] diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index b616ed35d99d7..f88155e4fc792 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,5 +1,4 @@ #![feature(array_windows)] -#![feature(control_flow_enum)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 1c492c53de7e1..9a5d3cceb914e 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,6 +1,5 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(associated_type_defaults)] -#![feature(control_flow_enum)] #![feature(rustc_private)] #![feature(try_blocks)] #![feature(let_chains)] diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 384d03106b1e8..b3b9a67b26e3d 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(alloc_layout_extra, control_flow_enum, decl_macro, iterator_try_reduce, never_type)] +#![feature(alloc_layout_extra, decl_macro, iterator_try_reduce, never_type)] #![allow(dead_code, unused_variables)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 7ad5cbc01ccf2..0853de601b040 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -6,7 +6,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(let_chains)] -#![feature(control_flow_enum)] #![feature(never_type)] #![feature(box_patterns)] #![recursion_limit = "256"] From deb05758c8d7e13599617f322be8c03b22d1d724 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 18 Jan 2023 11:41:34 -0700 Subject: [PATCH 15/18] rustdoc: put focus on the help link when opening it from keyboard This prevents some strange blur-event-related bugs with the "?" command by ensuring that the focus remains in the same spot when the settings area closes. --- src/librustdoc/html/static/js/main.js | 3 +++ tests/rustdoc-gui/settings.goml | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 9ceeeb5ae8fd8..6cb670d32a660 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1082,6 +1082,9 @@ function loadCss(cssUrl) { * Show the help popup menu. */ function showHelp() { + // Prevent `blur` events from being dispatched as a result of closing + // other modals. + getHelpButton().querySelector("a").focus(); const menu = getHelpMenu(true); if (menu.style.display === "none") { window.hideAllModals(); diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml index 72de41e41bae1..2114e2cc4c23d 100644 --- a/tests/rustdoc-gui/settings.goml +++ b/tests/rustdoc-gui/settings.goml @@ -203,6 +203,15 @@ press-key: "?" wait-for-css: ("#help-button .popover", {"display": "block"}) assert-css: ("#settings-menu .popover", {"display": "none"}) +// Now switch back to the settings popover, and make sure the keyboard +// shortcut works when a check box is selected. +click: "#settings-menu > a" +wait-for-css: ("#settings-menu .popover", {"display": "block"}) +focus: "#auto-hide-large-items" +press-key: "?" +wait-for-css: ("#settings-menu .popover", {"display": "none"}) +wait-for-css: ("#help-button .popover", {"display": "block"}) + // Now we go to the settings page to check that the CSS is loaded as expected. goto: "file://" + |DOC_PATH| + "/settings.html" wait-for: "#settings" From bb5fb53b30fd2216639ae85ab44ec4445e004556 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 18 Jan 2023 11:52:31 -0700 Subject: [PATCH 16/18] rustdoc: fix "?" keyboard command when radio button is focused This extends the special case with checkbox settings to also cover radios. --- src/librustdoc/html/static/js/main.js | 3 ++- tests/rustdoc-gui/settings.goml | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 6cb670d32a660..604ab147f6a16 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -390,7 +390,8 @@ function loadCss(cssUrl) { } if (document.activeElement.tagName === "INPUT" && - document.activeElement.type !== "checkbox") { + document.activeElement.type !== "checkbox" && + document.activeElement.type !== "radio") { switch (getVirtualKey(ev)) { case "Escape": handleEscape(ev); diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml index 2114e2cc4c23d..4c72ed51a4979 100644 --- a/tests/rustdoc-gui/settings.goml +++ b/tests/rustdoc-gui/settings.goml @@ -212,6 +212,16 @@ press-key: "?" wait-for-css: ("#settings-menu .popover", {"display": "none"}) wait-for-css: ("#help-button .popover", {"display": "block"}) +// Now switch back to the settings popover, and make sure the keyboard +// shortcut works when a check box is selected. +click: "#settings-menu > a" +wait-for-css: ("#settings-menu .popover", {"display": "block"}) +wait-for-css: ("#help-button .popover", {"display": "none"}) +focus: "#theme-system-preference" +press-key: "?" +wait-for-css: ("#settings-menu .popover", {"display": "none"}) +wait-for-css: ("#help-button .popover", {"display": "block"}) + // Now we go to the settings page to check that the CSS is loaded as expected. goto: "file://" + |DOC_PATH| + "/settings.html" wait-for: "#settings" From 9ee4df0e9cbe474a0f357ed00dd479a2dae65e23 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 18 Jan 2023 12:39:13 -0700 Subject: [PATCH 17/18] rustdoc: remove redundant rule `#settings .setting-line` Since the current version of settings.js always nests things below a div with ID `settings`, this rule always overrode the one above. --- src/librustdoc/html/static/css/settings.css | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css index 3fa478751737f..7211ffb779568 100644 --- a/src/librustdoc/html/static/css/settings.css +++ b/src/librustdoc/html/static/css/settings.css @@ -1,5 +1,5 @@ .setting-line { - margin: 0.6em 0 0.6em 0.3em; + margin: 1.2em 0.6em; position: relative; } @@ -55,10 +55,6 @@ cursor: pointer; } -#settings .setting-line { - margin: 1.2em 0.6em; -} - .setting-line .radio-line input:checked { box-shadow: inset 0 0 0 3px var(--main-background-color); background-color: var(--settings-input-color); From 34d595dda16cbcc7a14aea17db8c5328867ed94d Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 18 Jan 2023 12:48:24 -0700 Subject: [PATCH 18/18] rustdoc: add test case for setting-line margin on settings.html --- tests/rustdoc-gui/settings.goml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml index 72de41e41bae1..951ff4e30d2e3 100644 --- a/tests/rustdoc-gui/settings.goml +++ b/tests/rustdoc-gui/settings.goml @@ -8,6 +8,10 @@ assert-false: "#settings" click: "#settings-menu" wait-for: "#settings" assert-css: ("#settings", {"display": "block"}) + +// Store the line margin to compare with the settings.html later. +store-css: (setting_line_margin, ".setting-line", "margin") + // Let's close it by clicking on the same button. click: "#settings-menu" wait-for-css: ("#settings", {"display": "none"}) @@ -211,6 +215,9 @@ assert-css: (".setting-line", {"position": "relative"}) assert-attribute-false: ("#settings", {"class": "popover"}, CONTAINS) compare-elements-position: (".sub form", "#settings", ("x")) +// Check that setting-line has the same margin in this mode as in the popover. +assert-css: (".setting-line", {"margin": |setting_line_margin|}) + // We now check the display with JS disabled. assert-false: "noscript section" javascript: false