diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_hir_typeck/src/writeback.rs | 36 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/mir/interpret/queries.rs | 19 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/src/elaborate_drop.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/src/patch.rs | 22 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/mod.rs | 49 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/solve.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/solve/normalize.rs | 57 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/normalize.rs | 13 | 
8 files changed, 130 insertions, 70 deletions
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 807d62562db..4a171a08ef7 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -1,6 +1,12 @@ -// Type resolution: the phase that finds all the types in the AST with -// unresolved type variables and replaces "ty_var" types with their -// generic parameters. +//! During type inference, partially inferred terms are +//! represented using inference variables (ty::Infer). These don't appear in +//! the final [`ty::TypeckResults`] since all of the types should have been +//! inferred once typeck is done. +//! +//! When type inference is running however, having to update the typeck results +//! every time a new type is inferred would be unreasonably slow, so instead all +//! of the replacement happens at the end in [`FnCtxt::resolve_type_vars_in_body`], +//! which creates a new `TypeckResults` which doesn't contain any inference variables. use std::mem; @@ -26,15 +32,6 @@ use crate::FnCtxt; /////////////////////////////////////////////////////////////////////////// // Entry point -// During type inference, partially inferred types are -// represented using Type variables (ty::Infer). These don't appear in -// the final TypeckResults since all of the types should have been -// inferred once typeck is done. -// When type inference is running however, having to update the typeck -// typeck results every time a new type is inferred would be unreasonably slow, -// so instead all of the replacement happens at the end in -// resolve_type_vars_in_body, which creates a new TypeTables which -// doesn't contain any inference types. impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn resolve_type_vars_in_body( &self, @@ -89,14 +86,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } -/////////////////////////////////////////////////////////////////////////// -// The Writeback context. This visitor walks the HIR, checking the -// fn-specific typeck results to find references to types or regions. It -// resolves those regions to remove inference variables and writes the -// final result back into the master typeck results in the tcx. Here and -// there, it applies a few ad-hoc checks that were not convenient to -// do elsewhere. - +/// The Writeback context. This visitor walks the HIR, checking the +/// fn-specific typeck results to find inference variables. It resolves +/// those inference variables and writes the final result into the +/// `TypeckResults`. It also applies a few ad-hoc checks that were not +/// convenient to do elsewhere. struct WritebackCx<'cx, 'tcx> { fcx: &'cx FnCtxt<'cx, 'tcx>, @@ -877,7 +871,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { let cause = ObligationCause::misc(self.span.to_span(tcx), body_id); let at = self.fcx.at(&cause, self.fcx.param_env); let universes = vec![None; outer_exclusive_binder(value).as_usize()]; - match solve::deeply_normalize_with_skipped_universes_and_ambiguous_goals( + match solve::deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals( at, value, universes, ) { Ok((value, goals)) => { diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 4222a68e544..e5d1dda3aa0 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -115,15 +115,16 @@ impl<'tcx> TyCtxt<'tcx> { // @lcnr believes that successfully evaluating even though there are // used generic parameters is a bug of evaluation, so checking for it // here does feel somewhat sensible. - if !self.features().generic_const_exprs() && ct.args.has_non_region_param() { - let def_kind = self.def_kind(instance.def_id()); - assert!( - matches!( - def_kind, - DefKind::InlineConst | DefKind::AnonConst | DefKind::AssocConst - ), - "{cid:?} is {def_kind:?}", - ); + if !self.features().generic_const_exprs() + && ct.args.has_non_region_param() + // We only FCW for anon consts as repeat expr counts with anon consts are the only place + // that we have a back compat hack for. We don't need to check this is a const argument + // as only anon consts as const args should get evaluated "for the type system". + // + // If we don't *only* FCW anon consts we can wind up incorrectly FCW'ing uses of assoc + // consts in pattern positions. #140447 + && self.def_kind(instance.def_id()) == DefKind::AnonConst + { let mir_body = self.mir_for_ctfe(instance.def_id()); if mir_body.is_polymorphic { let Some(local_def_id) = ct.def.as_local() else { return }; diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index 6f867f8105d..73a58160a6a 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -376,7 +376,7 @@ where if self.tcx().features().async_drop() && self.elaborator.body().coroutine.is_some() && self.elaborator.allow_async_drops() - && !self.elaborator.body()[bb].is_cleanup + && !self.elaborator.patch_ref().block(self.elaborator.body(), bb).is_cleanup && drop_ty.needs_async_drop(self.tcx(), self.elaborator.typing_env()) { self.build_async_drop( diff --git a/compiler/rustc_mir_transform/src/patch.rs b/compiler/rustc_mir_transform/src/patch.rs index c7eb2a921c7..a872eae15f1 100644 --- a/compiler/rustc_mir_transform/src/patch.rs +++ b/compiler/rustc_mir_transform/src/patch.rs @@ -148,11 +148,20 @@ impl<'tcx> MirPatch<'tcx> { self.term_patch_map[bb].is_some() } + /// Universal getter for block data, either it is in 'old' blocks or in patched ones + pub(crate) fn block<'a>( + &'a self, + body: &'a Body<'tcx>, + bb: BasicBlock, + ) -> &'a BasicBlockData<'tcx> { + match bb.index().checked_sub(body.basic_blocks.len()) { + Some(new) => &self.new_blocks[new], + None => &body[bb], + } + } + pub(crate) fn terminator_loc(&self, body: &Body<'tcx>, bb: BasicBlock) -> Location { - let offset = match bb.index().checked_sub(body.basic_blocks.len()) { - Some(index) => self.new_blocks[index].statements.len(), - None => body[bb].statements.len(), - }; + let offset = self.block(body, bb).statements.len(); Location { block: bb, statement_index: offset } } @@ -284,10 +293,7 @@ impl<'tcx> MirPatch<'tcx> { } pub(crate) fn source_info_for_location(&self, body: &Body<'tcx>, loc: Location) -> SourceInfo { - let data = match loc.block.index().checked_sub(body.basic_blocks.len()) { - Some(new) => &self.new_blocks[new], - None => &body[loc.block], - }; + let data = self.block(body, loc.block); Self::source_info_for_index(data, loc) } } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 1c542ebbebd..968376678f3 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -58,13 +58,62 @@ mod tokenstream { } bitflags::bitflags! { + /// Restrictions applied while parsing. + /// + /// The parser maintains a bitset of restrictions it will honor while + /// parsing. This is essentially used as a way of tracking state of what + /// is being parsed and to change behavior based on that. #[derive(Clone, Copy, Debug)] struct Restrictions: u8 { + /// Restricts expressions for use in statement position. + /// + /// When expressions are used in various places, like statements or + /// match arms, this is used to stop parsing once certain tokens are + /// reached. + /// + /// For example, `if true {} & 1` with `STMT_EXPR` in effect is parsed + /// as two separate expression statements (`if` and a reference to 1). + /// Otherwise it is parsed as a bitwise AND where `if` is on the left + /// and 1 is on the right. const STMT_EXPR = 1 << 0; + /// Do not allow struct literals. + /// + /// There are several places in the grammar where we don't want to + /// allow struct literals because they can require lookahead, or + /// otherwise could be ambiguous or cause confusion. For example, + /// `if Foo {} {}` isn't clear if it is `Foo{}` struct literal, or + /// just `Foo` is the condition, followed by a consequent block, + /// followed by an empty block. + /// + /// See [RFC 92](https://rust-lang.github.io/rfcs/0092-struct-grammar.html). const NO_STRUCT_LITERAL = 1 << 1; + /// Used to provide better error messages for const generic arguments. + /// + /// An un-braced const generic argument is limited to a very small + /// subset of expressions. This is used to detect the situation where + /// an expression outside of that subset is used, and to suggest to + /// wrap the expression in braces. const CONST_EXPR = 1 << 2; + /// Allows `let` expressions. + /// + /// `let pattern = scrutinee` is parsed as an expression, but it is + /// only allowed in let chains (`if` and `while` conditions). + /// Otherwise it is not an expression (note that `let` in statement + /// positions is treated as a `StmtKind::Let` statement, which has a + /// slightly different grammar). const ALLOW_LET = 1 << 3; + /// Used to detect a missing `=>` in a match guard. + /// + /// This is used for error handling in a match guard to give a better + /// error message if the `=>` is missing. It is set when parsing the + /// guard expression. const IN_IF_GUARD = 1 << 4; + /// Used to detect the incorrect use of expressions in patterns. + /// + /// This is used for error handling while parsing a pattern. During + /// error recovery, this will be set to try to parse the pattern as an + /// expression, but halts parsing the expression when reaching certain + /// tokens like `=`. const IS_PAT = 1 << 5; } } diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs index 0c2451a80a7..5a5d16167d2 100644 --- a/compiler/rustc_trait_selection/src/solve.rs +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -11,6 +11,6 @@ pub use fulfill::{FulfillmentCtxt, NextSolverError}; pub(crate) use normalize::deeply_normalize_for_diagnostics; pub use normalize::{ deeply_normalize, deeply_normalize_with_skipped_universes, - deeply_normalize_with_skipped_universes_and_ambiguous_goals, + deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals, }; pub use select::InferCtxtSelectExt; diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index 5f1e63ab225..d903f94b489 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -45,9 +45,11 @@ where T: TypeFoldable<TyCtxt<'tcx>>, E: FromSolverError<'tcx, NextSolverError<'tcx>>, { - let (value, goals) = - deeply_normalize_with_skipped_universes_and_ambiguous_goals(at, value, universes)?; - assert_eq!(goals, vec![]); + let (value, coroutine_goals) = + deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals( + at, value, universes, + )?; + assert_eq!(coroutine_goals, vec![]); Ok(value) } @@ -59,9 +61,9 @@ where /// entered before passing `value` to the function. This is currently needed for /// `normalize_erasing_regions`, which skips binders as it walks through a type. /// -/// This returns a set of stalled obligations if the typing mode of the underlying infcx -/// has any stalled coroutine def ids. -pub fn deeply_normalize_with_skipped_universes_and_ambiguous_goals<'tcx, T, E>( +/// This returns a set of stalled obligations involving coroutines if the typing mode of +/// the underlying infcx has any stalled coroutine def ids. +pub fn deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals<'tcx, T, E>( at: At<'_, 'tcx>, value: T, universes: Vec<Option<UniverseIndex>>, @@ -71,11 +73,16 @@ where E: FromSolverError<'tcx, NextSolverError<'tcx>>, { let fulfill_cx = FulfillmentCtxt::new(at.infcx); - let mut folder = - NormalizationFolder { at, fulfill_cx, depth: 0, universes, stalled_goals: vec![] }; + let mut folder = NormalizationFolder { + at, + fulfill_cx, + depth: 0, + universes, + stalled_coroutine_goals: vec![], + }; let value = value.try_fold_with(&mut folder)?; let errors = folder.fulfill_cx.select_all_or_error(at.infcx); - if errors.is_empty() { Ok((value, folder.stalled_goals)) } else { Err(errors) } + if errors.is_empty() { Ok((value, folder.stalled_coroutine_goals)) } else { Err(errors) } } struct NormalizationFolder<'me, 'tcx, E> { @@ -83,7 +90,7 @@ struct NormalizationFolder<'me, 'tcx, E> { fulfill_cx: FulfillmentCtxt<'tcx, E>, depth: usize, universes: Vec<Option<UniverseIndex>>, - stalled_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>, + stalled_coroutine_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>, } impl<'tcx, E> NormalizationFolder<'_, 'tcx, E> @@ -182,7 +189,7 @@ where return Err(errors); } - self.stalled_goals.extend( + self.stalled_coroutine_goals.extend( self.fulfill_cx .drain_stalled_obligations_for_coroutines(self.at.infcx) .into_iter() @@ -298,13 +305,13 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_, fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { let infcx = self.at.infcx; - let result = - infcx.commit_if_ok(|_| { - deeply_normalize_with_skipped_universes_and_ambiguous_goals::< - _, - ScrubbedTraitError<'tcx>, - >(self.at, ty, vec![None; ty.outer_exclusive_binder().as_usize()]) - }); + let result: Result<_, Vec<ScrubbedTraitError<'tcx>>> = infcx.commit_if_ok(|_| { + deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals( + self.at, + ty, + vec![None; ty.outer_exclusive_binder().as_usize()], + ) + }); match result { Ok((ty, _)) => ty, Err(_) => ty.super_fold_with(self), @@ -313,13 +320,13 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_, fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { let infcx = self.at.infcx; - let result = - infcx.commit_if_ok(|_| { - deeply_normalize_with_skipped_universes_and_ambiguous_goals::< - _, - ScrubbedTraitError<'tcx>, - >(self.at, ct, vec![None; ct.outer_exclusive_binder().as_usize()]) - }); + let result: Result<_, Vec<ScrubbedTraitError<'tcx>>> = infcx.commit_if_ok(|_| { + deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals( + self.at, + ct, + vec![None; ct.outer_exclusive_binder().as_usize()], + ) + }); match result { Ok((ct, _)) => ct, Err(_) => ct.super_fold_with(self), diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index d38ddbc825c..5f0acd46f86 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -260,11 +260,14 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx } ty::Projection if !data.has_escaping_bound_vars() => { - // This branch is *mostly* just an optimization: when we don't - // have escaping bound vars, we don't need to replace them with - // placeholders (see branch below). *Also*, we know that we can - // register an obligation to *later* project, since we know - // there won't be bound vars there. + // When we don't have escaping bound vars we can normalize ambig aliases + // to inference variables (done in `normalize_projection_ty`). This would + // be wrong if there were escaping bound vars as even if we instantiated + // the bound vars with placeholders, we wouldn't be able to map them back + // after normalization succeeded. + // + // Also, as an optimization: when we don't have escaping bound vars, we don't + // need to replace them with placeholders (see branch below). let data = data.fold_with(self); let normalized_ty = project::normalize_projection_ty( self.selcx,  | 
