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 8c22df7395f1..638bde27d8c6 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -4,12 +4,13 @@ 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 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { } 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 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { } } + 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 000000000000..78922b59b27b --- /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 000000000000..5cedf3ddb0f6 --- /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 1b8822b0b2b7..88592fa0c84c 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 858046e72e9a..1b4c7b405702 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 25efbad26954..fd5c5489d79c 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 cd0e8e7b4a9e..fc44a566af21 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 d14672af71fd..3b2f15a40bf8 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 a8000aa3c8a8..e8ae9712a633 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 000000000000..edc7fa81abb4 --- /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 000000000000..fc8f480e706b --- /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 4f7c1fc96f13..ca6b01d8a8a7 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 @@ fn hook_special_const_fn( /// `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 @@ fn align_offset( 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 a61d3ab40a5c..cabc65e2c077 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -26,7 +26,7 @@ impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> { 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 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { 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 57007611a76c..8a9af300c066 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 @@ fn node_examined( _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 @@ fn node_examined( 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 e58669433e21..d5e4b4cb9e72 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -267,7 +267,7 @@ impl<'tcx> ty::visit::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { 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 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { if self.references_parent_regions { ControlFlow::Break(t) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -1439,7 +1439,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { 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 49dd1eb22f7f..8739228e207b 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1428,7 +1428,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { } 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 0aadc9f311b0..0d070f3d118e 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -416,13 +416,13 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { 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 visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { } } - 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 95c971c0d784..56cc1d8fadc0 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 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { 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 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { 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 24008f888143..079070be2798 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -92,7 +92,7 @@ fn visit_opaque(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> ControlFlo 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 26e8dd654c13..12a2abfa76a9 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -236,7 +236,7 @@ impl<'tcx> TypeVisitor<'tcx> for MentionsTy<'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 fb0f09198ccc..49ad3ce50b8f 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 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { 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 985cb6463a06..f235cb5ab450 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 @@ fn visit_binder>( 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 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { _ => {} } - 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 6b54ee9576f6..e22ba9785e1f 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -440,16 +440,16 @@ fn visit_binder>( 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 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { 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 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 8671f8d45a91..65b90aa3d79d 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -147,7 +147,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { } 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 @@ fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow { } 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 f2ab44ac97c8..be47a3e238c1 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1147,7 +1147,7 @@ impl<'tcx> ty::visit::TypeVisitor<'tcx> for ProhibitOpaqueTypes { 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 14e6aa6e0c17..1f95661ce9d5 100644 --- a/compiler/rustc_macros/src/type_visitable.rs +++ b/compiler/rustc_macros/src/type_visitable.rs @@ -26,7 +26,7 @@ fn visit_with<__V: ::rustc_middle::ty::visit::TypeVisitor<'tcx>>( __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 5ca4d260179c..250f3d0797eb 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -93,7 +93,7 @@ fn visit_with>( _: &mut F) -> ::std::ops::ControlFlow { - ::std::ops::ControlFlow::CONTINUE + ::std::ops::ControlFlow::Continue(()) } } )+ @@ -219,7 +219,7 @@ fn visit_with>( $($crate::ty::visit::TypeVisitable::visit_with( $variant_arg, $visitor )?;)* - ::std::ops::ControlFlow::CONTINUE + ::std::ops::ControlFlow::Continue(()) } $($output)* ) @@ -237,7 +237,7 @@ fn visit_with>( $($crate::ty::visit::TypeVisitable::visit_with( $variant_arg, $visitor )?;)* - ::std::ops::ControlFlow::CONTINUE + ::std::ops::ControlFlow::Continue(()) } $($output)* ) @@ -251,7 +251,7 @@ fn visit_with>( @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 e7cd497b206a..d44c6809bd83 100644 --- a/compiler/rustc_middle/src/mir/type_visitable.rs +++ b/compiler/rustc_middle/src/mir/type_visitable.rs @@ -4,6 +4,6 @@ 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 42fc78a4715f..a483945ccf26 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2481,7 +2481,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { 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 81ec18684fd8..7d4d35b7fdf9 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -367,7 +367,7 @@ fn try_fold_with>(self, _folder: &mut F) -> Result TypeVisitable<'tcx> for ty::AdtDef<'tcx> { fn visit_with>(&self, _visitor: &mut V) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -714,7 +714,7 @@ fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow | ty::Placeholder(..) | ty::Param(..) | ty::Never - | ty::Foreign(..) => ControlFlow::CONTINUE, + | ty::Foreign(..) => ControlFlow::Continue(()), } } } @@ -742,7 +742,7 @@ fn try_super_fold_with>( 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 @@ fn try_fold_with>(self, _folder: &mut F) -> Result 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 3f8252aefdc3..8720ee26b427 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2015,7 +2015,7 @@ impl<'tcx> TypeVisitor<'tcx> for ContainsTyVisitor<'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 ca4455581313..bee3cc4d7cb9 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -294,13 +294,13 @@ fn visit_binder>( 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 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) { ty.super_visit_with(self) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -394,7 +394,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { 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 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { if t.outer_exclusive_binder() > self.outer_index { ControlFlow::Break(FoundEscapingVars) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -524,7 +524,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { if r.bound_at_or_above_binder(self.outer_index) { ControlFlow::Break(FoundEscapingVars) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -547,7 +547,7 @@ fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow self.outer_index { ControlFlow::Break(FoundEscapingVars) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -575,7 +575,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -585,7 +585,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -596,7 +596,7 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -605,7 +605,7 @@ fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow) -> ControlFlow { // in the normalized form if self.just_constrained { if let ty::Alias(..) = t.kind() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } } @@ -666,7 +666,7 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { // 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 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { self.regions.insert(br.kind); } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -726,6 +726,6 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { ); } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index fac4997fcbf6..f67f24b43c4d 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -118,7 +118,7 @@ fn node_examined( // 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 @@ fn node_examined( | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::Goto { .. } - | TerminatorKind::SwitchInt { .. } => ControlFlow::CONTINUE, + | TerminatorKind::SwitchInt { .. } => ControlFlow::Continue(()), } } @@ -145,7 +145,7 @@ fn node_settled(&mut self, bb: BasicBlock) -> ControlFlow { } } - 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 c8fc69eb856a..cf13d4584a12 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 @@ fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow { #[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 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { 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 fb55bb4afaac..1c492c53de7e 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -112,7 +112,11 @@ impl<'tcx, V> DefIdVisitorSkeleton<'_, 'tcx, V> 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 @@ fn visit_projection_ty(&mut self, projection: ty::AliasTy<'tcx>) -> ControlFlow< }; 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 @@ fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow 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 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { | 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 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { // 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 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { } if self.def_id_visitor.shallow() { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { ty.super_visit_with(self) } @@ -319,7 +323,7 @@ fn visit_def_id( 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 @@ fn visit_def_id( self.ev.update(def_id, self.level); } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -1368,9 +1372,9 @@ fn visit_def_id( 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 @@ fn visit_def_id( 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 0edae34190c3..5f649852d0bb 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -614,12 +614,12 @@ fn new(tcx: TyCtxt<'tcx>, in_crate: InCrate) -> Self { 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 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { /// 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 71fb6058cd2c..f779d9dd8d93 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 visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { // 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 32b0f65176c1..434f75de02bf 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 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { 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 531aa23d6eac..f036a311d464 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -493,7 +493,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { && 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 visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { && 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 visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow { && 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 9a0e3d298eda..c9121212cd8f 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 visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { 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 visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { .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 c6ef13e185b2..1531c50760d5 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 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { .escaping .max(t.outer_exclusive_binder().as_usize() - self.outer_index.as_usize()); } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } #[inline] @@ -145,7 +145,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { } _ => {} } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow { @@ -153,7 +153,7 @@ fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow { 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 892a7afd799c..f398fb06c187 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 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { 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 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { // 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 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { ty::Float(_) => { if !self.adt_const_param { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } else { return ControlFlow::Break(ty); } @@ -172,13 +172,13 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { 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 0658836fb9cd..a2aad049998a 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 @@ pub(super) fn compute_projection_goal( &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 cd6e4d2bccd5..c8611294449e 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 @@ fn consider_impl_candidate( 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 @@ fn assemble_impl_candidates>( 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 @@ fn assemble_builtin_impl_candidates>( 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 @@ fn assemble_param_env_candidates>( 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 @@ fn assemble_alias_bound_candidates>( .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 579cd6a2d59c..32eb84635b53 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -313,6 +313,13 @@ fn evaluate_all( } }) } + + 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 0658836fb9cd..1d85d31705ad 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 @@ fn consider_impl_candidate( 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 @@ fn consider_impl_candidate( 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 @@ fn consider_impl_candidate( 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 @@ fn consider_assumption( _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 bbe175d5cc85..111758c77d99 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 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 @@ fn consider_impl_candidate( 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 @@ fn consider_impl_candidate( .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 @@ fn consider_assumption( _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 9b7feb505378..47e6c93016a0 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 @@ fn eq>( 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 @@ fn eq>( 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 1d85d31705ad..9ebcb4e4657d 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 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 @@ fn consider_builtin_sized_candidate( } 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 111758c77d99..362424b0d143 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::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 @@ fn consider_builtin_sized_candidate( } 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 c8611294449e..0a82c14e226f 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::{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 @@ pub(super) fn assemble_and_evaluate_candidates>( self.assemble_alias_bound_candidates(goal, &mut candidates); + self.assemble_object_bound_candidates(goal, &mut candidates); + candidates } @@ -272,4 +275,53 @@ fn assemble_alias_bound_candidates>( } } } + + 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 | 29 ++-- .../src/solve/project_goals.rs | 28 +++- .../src/solve/trait_goals.rs | 132 ++++++++++++++++-- 4 files changed, 171 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e68f27cc0fd5..db7dd2e5e75d 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2382,6 +2382,11 @@ pub fn trait_is_auto(self, trait_def_id: DefId) -> bool { 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 0a82c14e226f..0759c4233824 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -92,16 +92,26 @@ fn consider_impl_candidate( impl_def_id: DefId, ) -> QueryResult<'tcx>; - fn consider_builtin_sized_candidate( - ecx: &mut EvalCtxt<'_, 'tcx>, - goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx>; - fn consider_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, ) -> QueryResult<'tcx>; + + 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>, + ) -> QueryResult<'tcx>; } impl<'tcx> EvalCtxt<'_, 'tcx> { pub(super) fn assemble_and_evaluate_candidates>( @@ -198,7 +208,11 @@ fn assemble_builtin_impl_candidates>( ) { 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 @@ fn assemble_object_bound_candidates>( 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 9ebcb4e4657d..3c74de09802d 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 @@ fn consider_impl_candidate( }) } - 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 @@ fn consider_assumption( 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 362424b0d143..1f18de2e7a9e 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::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 @@ fn consider_impl_candidate( }) } - 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 @@ fn consider_assumption( 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 @@ fn discard_reservation_impl(&self, candidate: Candidate<'tcx>) -> Candidate<'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 0759c4233824..2336fb53aec2 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -112,7 +112,13 @@ fn consider_builtin_sized_candidate( 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 @@ fn assemble_builtin_impl_candidates>( 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 3c74de09802d..5c1f3f02e93a 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 @@ fn consider_builtin_sized_candidate( ) -> 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 1f18de2e7a9e..4d94265dc07f 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::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 @@ fn consider_trait_alias_candidate( } 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 47e6c93016a0..42f597c781d2 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 @@ fn eq>( 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 @@ fn eq>( }) } - #[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 5c1f3f02e93a..00c7edf0ef8a 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 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 @@ fn consider_assumption( ) -> 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 4d94265dc07f..d89759f4dd48 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_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 @@ fn consider_assumption( 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 d89759f4dd48..1ebcfd03c14e 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::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::{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 @@ 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) - }) + 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 @@ fn consider_builtin_sized_candidate( 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 @@ fn discard_reservation_impl(&self, candidate: Candidate<'tcx>) -> Candidate<'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 000000000000..bbc0c7725327 --- /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 46e7b09a55e1..57b91df2d070 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -6,7 +6,6 @@ #![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 3a2000233c5d..954e84c303b8 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 fb7ae6f1d242..a428180a4fa8 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 b616ed35d99d..f88155e4fc79 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 1c492c53de7e..9a5d3cceb914 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 384d03106b1e..b3b9a67b26e3 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 7ad5cbc01ccf..0853de601b04 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 9ceeeb5ae8fd..6cb670d32a66 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 72de41e41bae..2114e2cc4c23 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 6cb670d32a66..604ab147f6a1 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 2114e2cc4c23..4c72ed51a497 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 3fa478751737..7211ffb77956 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 72de41e41bae..951ff4e30d2e 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