Merge from rustc
This commit is contained in:
commit
54db9aaa37
98 changed files with 1623 additions and 881 deletions
33
Cargo.lock
33
Cargo.lock
|
|
@ -7,9 +7,18 @@ name = "addr2line"
|
|||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
|
||||
dependencies = [
|
||||
"gimli 0.28.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"gimli",
|
||||
"gimli 0.29.0",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
|
@ -287,7 +296,7 @@ version = "0.3.71"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"addr2line 0.21.0",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
|
|
@ -1575,6 +1584,17 @@ dependencies = [
|
|||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.1"
|
||||
|
|
@ -3234,7 +3254,7 @@ dependencies = [
|
|||
name = "run_make_support"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
"gimli 0.28.1",
|
||||
"object 0.34.0",
|
||||
"regex",
|
||||
"similar",
|
||||
|
|
@ -4686,6 +4706,7 @@ dependencies = [
|
|||
"rustc_span",
|
||||
"rustc_type_ir_macros",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5129,7 +5150,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
|||
name = "std"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"addr2line 0.22.0",
|
||||
"alloc",
|
||||
"cfg-if",
|
||||
"compiler_builtins",
|
||||
|
|
@ -5408,7 +5429,7 @@ version = "0.7.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4db52ee8fec06e119b692ef3dd2c4cf621a99204c1b8c47407870ed050305b9b"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
"gimli 0.28.1",
|
||||
"hashbrown",
|
||||
"object 0.32.2",
|
||||
"tracing",
|
||||
|
|
@ -5908,7 +5929,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "37a19a21a537f635c16c7576f22d0f2f7d63353c1337ad4ce0d8001c7952a25b"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"gimli",
|
||||
"gimli 0.28.1",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -294,12 +294,13 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns `rhs` sufficiently masked, truncated, and/or extended so that
|
||||
/// it can be used to shift `lhs`.
|
||||
/// Returns `rhs` sufficiently masked, truncated, and/or extended so that it can be used to shift
|
||||
/// `lhs`: it has the same size as `lhs`, and the value, when interpreted unsigned (no matter its
|
||||
/// type), will not exceed the size of `lhs`.
|
||||
///
|
||||
/// Shifts in MIR are all allowed to have mismatched LHS & RHS types.
|
||||
/// Shifts in MIR are all allowed to have mismatched LHS & RHS types, and signed RHS.
|
||||
/// The shift methods in `BuilderMethods`, however, are fully homogeneous
|
||||
/// (both parameters and the return type are all the same type).
|
||||
/// (both parameters and the return type are all the same size) and assume an unsigned RHS.
|
||||
///
|
||||
/// If `is_unchecked` is false, this masks the RHS to ensure it stays in-bounds,
|
||||
/// as the `BuilderMethods` shifts are UB for out-of-bounds shift amounts.
|
||||
|
|
|
|||
|
|
@ -110,8 +110,16 @@ pub trait BuilderMethods<'a, 'tcx>:
|
|||
fn frem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
|
||||
fn frem_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
|
||||
fn frem_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
|
||||
/// Generate a left-shift. Both operands must have the same size. The right operand must be
|
||||
/// interpreted as unsigned and can be assumed to be less than the size of the left operand.
|
||||
fn shl(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
|
||||
/// Generate a logical right-shift. Both operands must have the same size. The right operand
|
||||
/// must be interpreted as unsigned and can be assumed to be less than the size of the left
|
||||
/// operand.
|
||||
fn lshr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
|
||||
/// Generate an arithmetic right-shift. Both operands must have the same size. The right operand
|
||||
/// must be interpreted as unsigned and can be assumed to be less than the size of the left
|
||||
/// operand.
|
||||
fn ashr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
|
||||
fn unchecked_sadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
|
||||
fn unchecked_uadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
|
||||
|
|
|
|||
|
|
@ -223,7 +223,8 @@ fn expand_macro<'cx>(
|
|||
let arm_span = rhses[i].span();
|
||||
|
||||
// rhs has holes ( `$id` and `$(...)` that need filled)
|
||||
let tts = match transcribe(cx, &named_matches, rhs, rhs_span, transparency) {
|
||||
let id = cx.current_expansion.id;
|
||||
let tts = match transcribe(psess, &named_matches, rhs, rhs_span, transparency, id) {
|
||||
Ok(tts) => tts,
|
||||
Err(err) => {
|
||||
let guar = err.emit();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use crate::base::ExtCtxt;
|
||||
use crate::errors::{
|
||||
CountRepetitionMisplaced, MetaVarExprUnrecognizedVar, MetaVarsDifSeqMatchers, MustRepeatOnce,
|
||||
NoSyntaxVarsExprRepeat, VarStillRepeating,
|
||||
|
|
@ -9,12 +8,13 @@ use rustc_ast::mut_visit::{self, MutVisitor};
|
|||
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
|
||||
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{pluralize, Diag, PResult};
|
||||
use rustc_errors::{pluralize, Diag, DiagCtxt, PResult};
|
||||
use rustc_parse::parser::ParseNtResult;
|
||||
use rustc_span::hygiene::{LocalExpnId, Transparency};
|
||||
use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent};
|
||||
use rustc_span::{with_metavar_spans, Span, SyntaxContext};
|
||||
|
||||
use rustc_session::parse::ParseSess;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::mem;
|
||||
|
||||
|
|
@ -99,11 +99,12 @@ impl<'a> Iterator for Frame<'a> {
|
|||
///
|
||||
/// Along the way, we do some additional error checking.
|
||||
pub(super) fn transcribe<'a>(
|
||||
cx: &ExtCtxt<'a>,
|
||||
psess: &'a ParseSess,
|
||||
interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
|
||||
src: &mbe::Delimited,
|
||||
src_span: DelimSpan,
|
||||
transparency: Transparency,
|
||||
expand_id: LocalExpnId,
|
||||
) -> PResult<'a, TokenStream> {
|
||||
// Nothing for us to transcribe...
|
||||
if src.tts.is_empty() {
|
||||
|
|
@ -137,8 +138,9 @@ pub(super) fn transcribe<'a>(
|
|||
// again, and we are done transcribing.
|
||||
let mut result: Vec<TokenTree> = Vec::new();
|
||||
let mut result_stack = Vec::new();
|
||||
let mut marker = Marker(cx.current_expansion.id, transparency, Default::default());
|
||||
let mut marker = Marker(expand_id, transparency, Default::default());
|
||||
|
||||
let dcx = &psess.dcx;
|
||||
loop {
|
||||
// Look at the last frame on the stack.
|
||||
// If it still has a TokenTree we have not looked at yet, use that tree.
|
||||
|
|
@ -201,9 +203,7 @@ pub(super) fn transcribe<'a>(
|
|||
seq @ mbe::TokenTree::Sequence(_, seq_rep) => {
|
||||
match lockstep_iter_size(seq, interp, &repeats) {
|
||||
LockstepIterSize::Unconstrained => {
|
||||
return Err(cx
|
||||
.dcx()
|
||||
.create_err(NoSyntaxVarsExprRepeat { span: seq.span() }));
|
||||
return Err(dcx.create_err(NoSyntaxVarsExprRepeat { span: seq.span() }));
|
||||
}
|
||||
|
||||
LockstepIterSize::Contradiction(msg) => {
|
||||
|
|
@ -211,9 +211,9 @@ pub(super) fn transcribe<'a>(
|
|||
// happens when two meta-variables are used in the same repetition in a
|
||||
// sequence, but they come from different sequence matchers and repeat
|
||||
// different amounts.
|
||||
return Err(cx
|
||||
.dcx()
|
||||
.create_err(MetaVarsDifSeqMatchers { span: seq.span(), msg }));
|
||||
return Err(
|
||||
dcx.create_err(MetaVarsDifSeqMatchers { span: seq.span(), msg })
|
||||
);
|
||||
}
|
||||
|
||||
LockstepIterSize::Constraint(len, _) => {
|
||||
|
|
@ -227,9 +227,7 @@ pub(super) fn transcribe<'a>(
|
|||
// FIXME: this really ought to be caught at macro definition
|
||||
// time... It happens when the Kleene operator in the matcher and
|
||||
// the body for the same meta-variable do not match.
|
||||
return Err(cx
|
||||
.dcx()
|
||||
.create_err(MustRepeatOnce { span: sp.entire() }));
|
||||
return Err(dcx.create_err(MustRepeatOnce { span: sp.entire() }));
|
||||
}
|
||||
} else {
|
||||
// 0 is the initial counter (we have done 0 repetitions so far). `len`
|
||||
|
|
@ -274,7 +272,7 @@ pub(super) fn transcribe<'a>(
|
|||
MatchedSingle(ParseNtResult::Tt(tt)) => {
|
||||
// `tt`s are emitted into the output stream directly as "raw tokens",
|
||||
// without wrapping them into groups.
|
||||
maybe_use_metavar_location(cx, &stack, sp, tt, &mut marker)
|
||||
maybe_use_metavar_location(psess, &stack, sp, tt, &mut marker)
|
||||
}
|
||||
MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => {
|
||||
marker.visit_span(&mut sp);
|
||||
|
|
@ -295,7 +293,7 @@ pub(super) fn transcribe<'a>(
|
|||
}
|
||||
MatchedSeq(..) => {
|
||||
// We were unable to descend far enough. This is an error.
|
||||
return Err(cx.dcx().create_err(VarStillRepeating { span: sp, ident }));
|
||||
return Err(dcx.create_err(VarStillRepeating { span: sp, ident }));
|
||||
}
|
||||
};
|
||||
result.push(tt)
|
||||
|
|
@ -314,7 +312,7 @@ pub(super) fn transcribe<'a>(
|
|||
|
||||
// Replace meta-variable expressions with the result of their expansion.
|
||||
mbe::TokenTree::MetaVarExpr(sp, expr) => {
|
||||
transcribe_metavar_expr(cx, expr, interp, &mut marker, &repeats, &mut result, sp)?;
|
||||
transcribe_metavar_expr(dcx, expr, interp, &mut marker, &repeats, &mut result, sp)?;
|
||||
}
|
||||
|
||||
// If we are entering a new delimiter, we push its contents to the `stack` to be
|
||||
|
|
@ -374,7 +372,7 @@ pub(super) fn transcribe<'a>(
|
|||
/// combine with each other and not with tokens outside of the sequence.
|
||||
/// - The metavariable span comes from a different crate, then we prefer the more local span.
|
||||
fn maybe_use_metavar_location(
|
||||
cx: &ExtCtxt<'_>,
|
||||
psess: &ParseSess,
|
||||
stack: &[Frame<'_>],
|
||||
mut metavar_span: Span,
|
||||
orig_tt: &TokenTree,
|
||||
|
|
@ -412,7 +410,7 @@ fn maybe_use_metavar_location(
|
|||
&& insert(mspans, dspan.entire(), metavar_span)
|
||||
}),
|
||||
};
|
||||
if no_collision || cx.source_map().is_imported(metavar_span) {
|
||||
if no_collision || psess.source_map().is_imported(metavar_span) {
|
||||
return orig_tt.clone();
|
||||
}
|
||||
|
||||
|
|
@ -573,7 +571,7 @@ fn lockstep_iter_size(
|
|||
/// * `[ $( ${count(foo, 1)} ),* ]` will return an error because `${count(foo, 1)}` is
|
||||
/// declared inside a single repetition and the index `1` implies two nested repetitions.
|
||||
fn count_repetitions<'a>(
|
||||
cx: &ExtCtxt<'a>,
|
||||
dcx: &'a DiagCtxt,
|
||||
depth_user: usize,
|
||||
mut matched: &NamedMatch,
|
||||
repeats: &[(usize, usize)],
|
||||
|
|
@ -610,7 +608,7 @@ fn count_repetitions<'a>(
|
|||
.and_then(|el| el.checked_sub(repeats.len()))
|
||||
.unwrap_or_default();
|
||||
if depth_user > depth_max {
|
||||
return Err(out_of_bounds_err(cx, depth_max + 1, sp.entire(), "count"));
|
||||
return Err(out_of_bounds_err(dcx, depth_max + 1, sp.entire(), "count"));
|
||||
}
|
||||
|
||||
// `repeats` records all of the nested levels at which we are currently
|
||||
|
|
@ -626,7 +624,7 @@ fn count_repetitions<'a>(
|
|||
}
|
||||
|
||||
if let MatchedSingle(_) = matched {
|
||||
return Err(cx.dcx().create_err(CountRepetitionMisplaced { span: sp.entire() }));
|
||||
return Err(dcx.create_err(CountRepetitionMisplaced { span: sp.entire() }));
|
||||
}
|
||||
|
||||
count(depth_user, depth_max, matched)
|
||||
|
|
@ -634,7 +632,7 @@ fn count_repetitions<'a>(
|
|||
|
||||
/// Returns a `NamedMatch` item declared on the LHS given an arbitrary [Ident]
|
||||
fn matched_from_ident<'ctx, 'interp, 'rslt>(
|
||||
cx: &ExtCtxt<'ctx>,
|
||||
dcx: &'ctx DiagCtxt,
|
||||
ident: Ident,
|
||||
interp: &'interp FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
|
||||
) -> PResult<'ctx, &'rslt NamedMatch>
|
||||
|
|
@ -643,12 +641,12 @@ where
|
|||
{
|
||||
let span = ident.span;
|
||||
let key = MacroRulesNormalizedIdent::new(ident);
|
||||
interp.get(&key).ok_or_else(|| cx.dcx().create_err(MetaVarExprUnrecognizedVar { span, key }))
|
||||
interp.get(&key).ok_or_else(|| dcx.create_err(MetaVarExprUnrecognizedVar { span, key }))
|
||||
}
|
||||
|
||||
/// Used by meta-variable expressions when an user input is out of the actual declared bounds. For
|
||||
/// example, index(999999) in an repetition of only three elements.
|
||||
fn out_of_bounds_err<'a>(cx: &ExtCtxt<'a>, max: usize, span: Span, ty: &str) -> Diag<'a> {
|
||||
fn out_of_bounds_err<'a>(dcx: &'a DiagCtxt, max: usize, span: Span, ty: &str) -> Diag<'a> {
|
||||
let msg = if max == 0 {
|
||||
format!(
|
||||
"meta-variable expression `{ty}` with depth parameter \
|
||||
|
|
@ -660,11 +658,11 @@ fn out_of_bounds_err<'a>(cx: &ExtCtxt<'a>, max: usize, span: Span, ty: &str) ->
|
|||
must be less than {max}"
|
||||
)
|
||||
};
|
||||
cx.dcx().struct_span_err(span, msg)
|
||||
dcx.struct_span_err(span, msg)
|
||||
}
|
||||
|
||||
fn transcribe_metavar_expr<'a>(
|
||||
cx: &ExtCtxt<'a>,
|
||||
dcx: &'a DiagCtxt,
|
||||
expr: &MetaVarExpr,
|
||||
interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
|
||||
marker: &mut Marker,
|
||||
|
|
@ -679,8 +677,8 @@ fn transcribe_metavar_expr<'a>(
|
|||
};
|
||||
match *expr {
|
||||
MetaVarExpr::Count(original_ident, depth) => {
|
||||
let matched = matched_from_ident(cx, original_ident, interp)?;
|
||||
let count = count_repetitions(cx, depth, matched, repeats, sp)?;
|
||||
let matched = matched_from_ident(dcx, original_ident, interp)?;
|
||||
let count = count_repetitions(dcx, depth, matched, repeats, sp)?;
|
||||
let tt = TokenTree::token_alone(
|
||||
TokenKind::lit(token::Integer, sym::integer(count), None),
|
||||
visited_span(),
|
||||
|
|
@ -689,7 +687,7 @@ fn transcribe_metavar_expr<'a>(
|
|||
}
|
||||
MetaVarExpr::Ignore(original_ident) => {
|
||||
// Used to ensure that `original_ident` is present in the LHS
|
||||
let _ = matched_from_ident(cx, original_ident, interp)?;
|
||||
let _ = matched_from_ident(dcx, original_ident, interp)?;
|
||||
}
|
||||
MetaVarExpr::Index(depth) => match repeats.iter().nth_back(depth) {
|
||||
Some((index, _)) => {
|
||||
|
|
@ -698,7 +696,7 @@ fn transcribe_metavar_expr<'a>(
|
|||
visited_span(),
|
||||
));
|
||||
}
|
||||
None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "index")),
|
||||
None => return Err(out_of_bounds_err(dcx, repeats.len(), sp.entire(), "index")),
|
||||
},
|
||||
MetaVarExpr::Len(depth) => match repeats.iter().nth_back(depth) {
|
||||
Some((_, length)) => {
|
||||
|
|
@ -707,7 +705,7 @@ fn transcribe_metavar_expr<'a>(
|
|||
visited_span(),
|
||||
));
|
||||
}
|
||||
None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "len")),
|
||||
None => return Err(out_of_bounds_err(dcx, repeats.len(), sp.entire(), "len")),
|
||||
},
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -449,7 +449,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateBound<'_, 'tcx> {
|
|||
pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
impl_m_def_id: LocalDefId,
|
||||
) -> Result<&'tcx DefIdMap<ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed> {
|
||||
) -> Result<&'tcx DefIdMap<ty::EarlyBinder<'tcx, Ty<'tcx>>>, ErrorGuaranteed> {
|
||||
let impl_m = tcx.opt_associated_item(impl_m_def_id.to_def_id()).unwrap();
|
||||
let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
|
||||
let impl_trait_ref =
|
||||
|
|
|
|||
|
|
@ -1277,7 +1277,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
|
|||
}
|
||||
|
||||
#[instrument(level = "debug", skip(tcx))]
|
||||
fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<'_>> {
|
||||
fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFnSig<'_>> {
|
||||
use rustc_hir::Node::*;
|
||||
use rustc_hir::*;
|
||||
|
||||
|
|
|
|||
|
|
@ -82,14 +82,14 @@ fn opaque_type_bounds<'tcx>(
|
|||
pub(super) fn explicit_item_bounds(
|
||||
tcx: TyCtxt<'_>,
|
||||
def_id: LocalDefId,
|
||||
) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> {
|
||||
) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, Span)]> {
|
||||
explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::All)
|
||||
}
|
||||
|
||||
pub(super) fn explicit_item_super_predicates(
|
||||
tcx: TyCtxt<'_>,
|
||||
def_id: LocalDefId,
|
||||
) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> {
|
||||
) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, Span)]> {
|
||||
explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::SelfOnly)
|
||||
}
|
||||
|
||||
|
|
@ -97,7 +97,7 @@ pub(super) fn explicit_item_bounds_with_filter(
|
|||
tcx: TyCtxt<'_>,
|
||||
def_id: LocalDefId,
|
||||
filter: PredicateFilter,
|
||||
) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> {
|
||||
) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, Span)]> {
|
||||
match tcx.opt_rpitit_info(def_id.to_def_id()) {
|
||||
// RPITIT's bounds are the same as opaque type bounds, but with
|
||||
// a projection self type.
|
||||
|
|
@ -166,7 +166,7 @@ pub(super) fn explicit_item_bounds_with_filter(
|
|||
ty::EarlyBinder::bind(bounds)
|
||||
}
|
||||
|
||||
pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<ty::Clauses<'_>> {
|
||||
pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<'_, ty::Clauses<'_>> {
|
||||
tcx.explicit_item_bounds(def_id).map_bound(|bounds| {
|
||||
tcx.mk_clauses_from_iter(util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)))
|
||||
})
|
||||
|
|
@ -175,7 +175,7 @@ pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<ty:
|
|||
pub(super) fn item_super_predicates(
|
||||
tcx: TyCtxt<'_>,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<ty::Clauses<'_>> {
|
||||
) -> ty::EarlyBinder<'_, ty::Clauses<'_>> {
|
||||
tcx.explicit_item_super_predicates(def_id).map_bound(|bounds| {
|
||||
tcx.mk_clauses_from_iter(
|
||||
util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)).filter_only_self(),
|
||||
|
|
@ -186,7 +186,7 @@ pub(super) fn item_super_predicates(
|
|||
pub(super) fn item_non_self_assumptions(
|
||||
tcx: TyCtxt<'_>,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<ty::Clauses<'_>> {
|
||||
) -> ty::EarlyBinder<'_, ty::Clauses<'_>> {
|
||||
let all_bounds: FxIndexSet<_> = tcx.item_bounds(def_id).skip_binder().iter().collect();
|
||||
let own_bounds: FxIndexSet<_> =
|
||||
tcx.item_super_predicates(def_id).skip_binder().iter().collect();
|
||||
|
|
|
|||
|
|
@ -309,7 +309,7 @@ fn get_path_containing_arg_in_pat<'hir>(
|
|||
arg_path
|
||||
}
|
||||
|
||||
pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty<'_>> {
|
||||
pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, Ty<'_>> {
|
||||
use rustc_hir::*;
|
||||
use rustc_middle::ty::Ty;
|
||||
|
||||
|
|
@ -512,7 +512,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
|
|||
pub(super) fn type_of_opaque(
|
||||
tcx: TyCtxt<'_>,
|
||||
def_id: DefId,
|
||||
) -> Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
|
||||
) -> Result<ty::EarlyBinder<'_, Ty<'_>>, CyclePlaceholder> {
|
||||
if let Some(def_id) = def_id.as_local() {
|
||||
use rustc_hir::*;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use super::utils::*;
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct ExplicitPredicatesMap<'tcx> {
|
||||
map: FxIndexMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>,
|
||||
map: FxIndexMap<DefId, ty::EarlyBinder<'tcx, RequiredPredicates<'tcx>>>,
|
||||
}
|
||||
|
||||
impl<'tcx> ExplicitPredicatesMap<'tcx> {
|
||||
|
|
@ -18,7 +18,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
|
|||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
) -> &ty::EarlyBinder<RequiredPredicates<'tcx>> {
|
||||
) -> &ty::EarlyBinder<'tcx, RequiredPredicates<'tcx>> {
|
||||
self.map.entry(def_id).or_insert_with(|| {
|
||||
let predicates = if def_id.is_local() {
|
||||
tcx.explicit_predicates_of(def_id)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use super::utils::*;
|
|||
/// now be filled with inferred predicates.
|
||||
pub(super) fn infer_predicates(
|
||||
tcx: TyCtxt<'_>,
|
||||
) -> FxIndexMap<DefId, ty::EarlyBinder<RequiredPredicates<'_>>> {
|
||||
) -> FxIndexMap<DefId, ty::EarlyBinder<'_, RequiredPredicates<'_>>> {
|
||||
debug!("infer_predicates");
|
||||
|
||||
let mut explicit_map = ExplicitPredicatesMap::new();
|
||||
|
|
@ -101,7 +101,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
global_inferred_outlives: &FxIndexMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>,
|
||||
global_inferred_outlives: &FxIndexMap<DefId, ty::EarlyBinder<'tcx, RequiredPredicates<'tcx>>>,
|
||||
required_predicates: &mut RequiredPredicates<'tcx>,
|
||||
explicit_map: &mut ExplicitPredicatesMap<'tcx>,
|
||||
) {
|
||||
|
|
@ -322,7 +322,7 @@ fn check_inferred_predicates<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
global_inferred_outlives: &FxIndexMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>,
|
||||
global_inferred_outlives: &FxIndexMap<DefId, ty::EarlyBinder<'tcx, RequiredPredicates<'tcx>>>,
|
||||
required_predicates: &mut RequiredPredicates<'tcx>,
|
||||
) {
|
||||
// Load the current set of inferred and explicit predicates from `global_inferred_outlives`
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ fn impl_trait_ref_has_enough_non_local_candidates<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
infer_span: Span,
|
||||
trait_def_id: DefId,
|
||||
binder: EarlyBinder<TraitRef<'tcx>>,
|
||||
binder: EarlyBinder<'tcx, TraitRef<'tcx>>,
|
||||
mut did_has_local_parent: impl FnMut(DefId) -> bool,
|
||||
) -> bool {
|
||||
let infcx = tcx
|
||||
|
|
|
|||
|
|
@ -3757,7 +3757,7 @@ declare_lint! {
|
|||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// ```rust,edition2018,compile_fail
|
||||
/// #![deny(rust_2021_incompatible_or_patterns)]
|
||||
///
|
||||
/// macro_rules! match_any {
|
||||
|
|
@ -3797,7 +3797,7 @@ declare_lint! {
|
|||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// ```rust,edition2018,compile_fail
|
||||
/// #![deny(rust_2021_prelude_collisions)]
|
||||
///
|
||||
/// trait Foo {
|
||||
|
|
|
|||
|
|
@ -1074,7 +1074,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
self,
|
||||
index: DefIndex,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> {
|
||||
) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> {
|
||||
let lazy = self.root.tables.explicit_item_bounds.get(self, index);
|
||||
let output = if lazy.is_default() {
|
||||
&mut []
|
||||
|
|
@ -1088,7 +1088,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
self,
|
||||
index: DefIndex,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> {
|
||||
) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> {
|
||||
let lazy = self.root.tables.explicit_item_super_predicates.get(self, index);
|
||||
let output = if lazy.is_default() {
|
||||
&mut []
|
||||
|
|
|
|||
|
|
@ -418,19 +418,19 @@ define_tables! {
|
|||
// As an optimization, we only store this for trait aliases,
|
||||
// since it's identical to super_predicates_of for traits.
|
||||
implied_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>,
|
||||
type_of: Table<DefIndex, LazyValue<ty::EarlyBinder<Ty<'static>>>>,
|
||||
type_of: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, Ty<'static>>>>,
|
||||
variances_of: Table<DefIndex, LazyArray<ty::Variance>>,
|
||||
fn_sig: Table<DefIndex, LazyValue<ty::EarlyBinder<ty::PolyFnSig<'static>>>>,
|
||||
fn_sig: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, ty::PolyFnSig<'static>>>>,
|
||||
codegen_fn_attrs: Table<DefIndex, LazyValue<CodegenFnAttrs>>,
|
||||
impl_trait_header: Table<DefIndex, LazyValue<ty::ImplTraitHeader<'static>>>,
|
||||
const_param_default: Table<DefIndex, LazyValue<ty::EarlyBinder<rustc_middle::ty::Const<'static>>>>,
|
||||
const_param_default: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, rustc_middle::ty::Const<'static>>>>,
|
||||
object_lifetime_default: Table<DefIndex, LazyValue<ObjectLifetimeDefault>>,
|
||||
optimized_mir: Table<DefIndex, LazyValue<mir::Body<'static>>>,
|
||||
mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>,
|
||||
closure_saved_names_of_captured_variables: Table<DefIndex, LazyValue<IndexVec<FieldIdx, Symbol>>>,
|
||||
mir_coroutine_witnesses: Table<DefIndex, LazyValue<mir::CoroutineLayout<'static>>>,
|
||||
promoted_mir: Table<DefIndex, LazyValue<IndexVec<mir::Promoted, mir::Body<'static>>>>,
|
||||
thir_abstract_const: Table<DefIndex, LazyValue<ty::EarlyBinder<ty::Const<'static>>>>,
|
||||
thir_abstract_const: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, ty::Const<'static>>>>,
|
||||
impl_parent: Table<DefIndex, RawDefId>,
|
||||
constness: Table<DefIndex, hir::Constness>,
|
||||
defaultness: Table<DefIndex, hir::Defaultness>,
|
||||
|
|
@ -459,7 +459,7 @@ define_tables! {
|
|||
macro_definition: Table<DefIndex, LazyValue<ast::DelimArgs>>,
|
||||
proc_macro: Table<DefIndex, MacroKind>,
|
||||
deduced_param_attrs: Table<DefIndex, LazyArray<DeducedParamAttrs>>,
|
||||
trait_impl_trait_tys: Table<DefIndex, LazyValue<DefIdMap<ty::EarlyBinder<Ty<'static>>>>>,
|
||||
trait_impl_trait_tys: Table<DefIndex, LazyValue<DefIdMap<ty::EarlyBinder<'static, Ty<'static>>>>>,
|
||||
doc_link_resolutions: Table<DefIndex, LazyValue<DocLinkResMap>>,
|
||||
doc_link_traits_in_scope: Table<DefIndex, LazyArray<DefId>>,
|
||||
assumed_wf_types_for_rpitit: Table<DefIndex, LazyArray<(Ty<'static>, Span)>>,
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ macro_rules! arena_types {
|
|||
[decode] trait_impl_trait_tys:
|
||||
rustc_data_structures::unord::UnordMap<
|
||||
rustc_hir::def_id::DefId,
|
||||
rustc_middle::ty::EarlyBinder<rustc_middle::ty::Ty<'tcx>>
|
||||
rustc_middle::ty::EarlyBinder<'tcx, rustc_middle::ty::Ty<'tcx>>
|
||||
>,
|
||||
[] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>,
|
||||
[] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<'tcx>,
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
LocalModDefId::new_unchecked(id)
|
||||
}
|
||||
|
||||
pub fn impl_subject(self, def_id: DefId) -> EarlyBinder<ImplSubject<'tcx>> {
|
||||
pub fn impl_subject(self, def_id: DefId) -> EarlyBinder<'tcx, ImplSubject<'tcx>> {
|
||||
match self.impl_trait_ref(def_id) {
|
||||
Some(t) => t.map_bound(ImplSubject::Trait),
|
||||
None => self.type_of(def_id).map_bound(ImplSubject::Inherent),
|
||||
|
|
|
|||
|
|
@ -220,7 +220,10 @@ pub enum Const<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> Const<'tcx> {
|
||||
pub fn identity_unevaluated(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::EarlyBinder<Const<'tcx>> {
|
||||
pub fn identity_unevaluated(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
|
||||
ty::EarlyBinder::bind(Const::Unevaluated(
|
||||
UnevaluatedConst {
|
||||
def: def_id,
|
||||
|
|
|
|||
|
|
@ -624,7 +624,7 @@ impl<'tcx> Body<'tcx> {
|
|||
|
||||
/// Returns the return type; it always return first element from `local_decls` array.
|
||||
#[inline]
|
||||
pub fn bound_return_ty(&self) -> ty::EarlyBinder<Ty<'tcx>> {
|
||||
pub fn bound_return_ty(&self) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
|
||||
ty::EarlyBinder::bind(self.local_decls[RETURN_PLACE].ty)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1008,8 +1008,8 @@ pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>;
|
|||
/// element:
|
||||
///
|
||||
/// - [`Downcast`](ProjectionElem::Downcast): This projection sets the place's variant index to the
|
||||
/// given one, and makes no other changes. A `Downcast` projection on a place with its variant
|
||||
/// index already set is not well-formed.
|
||||
/// given one, and makes no other changes. A `Downcast` projection must always be followed
|
||||
/// immediately by a `Field` projection.
|
||||
/// - [`Field`](ProjectionElem::Field): `Field` projections take their parent place and create a
|
||||
/// place referring to one of the fields of the type. The resulting address is the parent
|
||||
/// address, plus the offset of the field. The type becomes the type of the field. If the parent
|
||||
|
|
|
|||
|
|
@ -114,9 +114,11 @@ impl EraseType for Result<CoerceUnsizedInfo, rustc_errors::ErrorGuaranteed> {
|
|||
type Result = [u8; size_of::<Result<CoerceUnsizedInfo, rustc_errors::ErrorGuaranteed>>()];
|
||||
}
|
||||
|
||||
impl EraseType for Result<Option<ty::EarlyBinder<ty::Const<'_>>>, rustc_errors::ErrorGuaranteed> {
|
||||
impl EraseType
|
||||
for Result<Option<ty::EarlyBinder<'_, ty::Const<'_>>>, rustc_errors::ErrorGuaranteed>
|
||||
{
|
||||
type Result = [u8; size_of::<
|
||||
Result<Option<ty::EarlyBinder<ty::Const<'static>>>, rustc_errors::ErrorGuaranteed>,
|
||||
Result<Option<ty::EarlyBinder<'static, ty::Const<'static>>>, rustc_errors::ErrorGuaranteed>,
|
||||
>()];
|
||||
}
|
||||
|
||||
|
|
@ -165,8 +167,8 @@ impl EraseType for Result<&'_ ty::List<Ty<'_>>, ty::util::AlwaysRequiresDrop> {
|
|||
[u8; size_of::<Result<&'static ty::List<Ty<'static>>, ty::util::AlwaysRequiresDrop>>()];
|
||||
}
|
||||
|
||||
impl EraseType for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
|
||||
type Result = [u8; size_of::<Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder>>()];
|
||||
impl EraseType for Result<ty::EarlyBinder<'_, Ty<'_>>, CyclePlaceholder> {
|
||||
type Result = [u8; size_of::<Result<ty::EarlyBinder<'static, Ty<'_>>, CyclePlaceholder>>()];
|
||||
}
|
||||
|
||||
impl<T> EraseType for Option<&'_ T> {
|
||||
|
|
@ -185,15 +187,15 @@ impl EraseType for Option<ty::ImplTraitHeader<'_>> {
|
|||
type Result = [u8; size_of::<Option<ty::ImplTraitHeader<'static>>>()];
|
||||
}
|
||||
|
||||
impl EraseType for Option<ty::EarlyBinder<Ty<'_>>> {
|
||||
type Result = [u8; size_of::<Option<ty::EarlyBinder<Ty<'static>>>>()];
|
||||
impl EraseType for Option<ty::EarlyBinder<'_, Ty<'_>>> {
|
||||
type Result = [u8; size_of::<Option<ty::EarlyBinder<'static, Ty<'static>>>>()];
|
||||
}
|
||||
|
||||
impl EraseType for rustc_hir::MaybeOwner<'_> {
|
||||
type Result = [u8; size_of::<rustc_hir::MaybeOwner<'static>>()];
|
||||
}
|
||||
|
||||
impl<T: EraseType> EraseType for ty::EarlyBinder<T> {
|
||||
impl<T: EraseType> EraseType for ty::EarlyBinder<'_, T> {
|
||||
type Result = T::Result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ rustc_queries! {
|
|||
|
||||
/// Given the def_id of a const-generic parameter, computes the associated default const
|
||||
/// parameter. e.g. `fn example<const N: usize=3>` called on `N` would return `3`.
|
||||
query const_param_default(param: DefId) -> ty::EarlyBinder<ty::Const<'tcx>> {
|
||||
query const_param_default(param: DefId) -> ty::EarlyBinder<'tcx, ty::Const<'tcx>> {
|
||||
desc { |tcx| "computing const default for a given parameter `{}`", tcx.def_path_str(param) }
|
||||
cache_on_disk_if { param.is_local() }
|
||||
separate_provide_extern
|
||||
|
|
@ -219,7 +219,7 @@ rustc_queries! {
|
|||
/// to an alias, it will "skip" this alias to return the aliased type.
|
||||
///
|
||||
/// [`DefId`]: rustc_hir::def_id::DefId
|
||||
query type_of(key: DefId) -> ty::EarlyBinder<Ty<'tcx>> {
|
||||
query type_of(key: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
|
||||
desc { |tcx|
|
||||
"{action} `{path}`",
|
||||
action = {
|
||||
|
|
@ -240,7 +240,7 @@ rustc_queries! {
|
|||
/// Specialized instance of `type_of` that detects cycles that are due to
|
||||
/// revealing opaque because of an auto trait bound. Unless `CyclePlaceholder` needs
|
||||
/// to be handled separately, call `type_of` instead.
|
||||
query type_of_opaque(key: DefId) -> Result<ty::EarlyBinder<Ty<'tcx>>, CyclePlaceholder> {
|
||||
query type_of_opaque(key: DefId) -> Result<ty::EarlyBinder<'tcx, Ty<'tcx>>, CyclePlaceholder> {
|
||||
desc { |tcx|
|
||||
"computing type of opaque `{path}`",
|
||||
path = tcx.def_path_str(key),
|
||||
|
|
@ -257,7 +257,7 @@ rustc_queries! {
|
|||
}
|
||||
|
||||
query collect_return_position_impl_trait_in_trait_tys(key: DefId)
|
||||
-> Result<&'tcx DefIdMap<ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed>
|
||||
-> Result<&'tcx DefIdMap<ty::EarlyBinder<'tcx, Ty<'tcx>>>, ErrorGuaranteed>
|
||||
{
|
||||
desc { "comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process" }
|
||||
cache_on_disk_if { key.is_local() }
|
||||
|
|
@ -363,7 +363,7 @@ rustc_queries! {
|
|||
/// `key` is the `DefId` of the associated type or opaque type.
|
||||
///
|
||||
/// Bounds from the parent (e.g. with nested impl trait) are not included.
|
||||
query explicit_item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> {
|
||||
query explicit_item_bounds(key: DefId) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> {
|
||||
desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
|
||||
cache_on_disk_if { key.is_local() }
|
||||
separate_provide_extern
|
||||
|
|
@ -373,7 +373,7 @@ rustc_queries! {
|
|||
/// share the `Self` type of the item. These are a subset of the bounds
|
||||
/// that may explicitly be used for things like closure signature
|
||||
/// deduction.
|
||||
query explicit_item_super_predicates(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> {
|
||||
query explicit_item_super_predicates(key: DefId) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> {
|
||||
desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
|
||||
cache_on_disk_if { key.is_local() }
|
||||
separate_provide_extern
|
||||
|
|
@ -399,15 +399,15 @@ rustc_queries! {
|
|||
/// ```
|
||||
///
|
||||
/// Bounds from the parent (e.g. with nested impl trait) are not included.
|
||||
query item_bounds(key: DefId) -> ty::EarlyBinder<ty::Clauses<'tcx>> {
|
||||
query item_bounds(key: DefId) -> ty::EarlyBinder<'tcx, ty::Clauses<'tcx>> {
|
||||
desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
|
||||
query item_super_predicates(key: DefId) -> ty::EarlyBinder<ty::Clauses<'tcx>> {
|
||||
query item_super_predicates(key: DefId) -> ty::EarlyBinder<'tcx, ty::Clauses<'tcx>> {
|
||||
desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
|
||||
query item_non_self_assumptions(key: DefId) -> ty::EarlyBinder<ty::Clauses<'tcx>> {
|
||||
query item_non_self_assumptions(key: DefId) -> ty::EarlyBinder<'tcx, ty::Clauses<'tcx>> {
|
||||
desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
|
||||
|
|
@ -504,7 +504,7 @@ rustc_queries! {
|
|||
/// Try to build an abstract representation of the given constant.
|
||||
query thir_abstract_const(
|
||||
key: DefId
|
||||
) -> Result<Option<ty::EarlyBinder<ty::Const<'tcx>>>, ErrorGuaranteed> {
|
||||
) -> Result<Option<ty::EarlyBinder<'tcx, ty::Const<'tcx>>>, ErrorGuaranteed> {
|
||||
desc {
|
||||
|tcx| "building an abstract representation for `{}`", tcx.def_path_str(key),
|
||||
}
|
||||
|
|
@ -704,7 +704,7 @@ rustc_queries! {
|
|||
separate_provide_extern
|
||||
}
|
||||
|
||||
query adt_sized_constraint(key: DefId) -> Option<ty::EarlyBinder<Ty<'tcx>>> {
|
||||
query adt_sized_constraint(key: DefId) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
|
||||
desc { |tcx| "computing the `Sized` constraint for `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
|
||||
|
|
@ -849,7 +849,7 @@ rustc_queries! {
|
|||
|
||||
query self_ty_of_trait_impl_enabling_order_dep_trait_object_hack(
|
||||
key: DefId
|
||||
) -> Option<ty::EarlyBinder<ty::Ty<'tcx>>> {
|
||||
) -> Option<ty::EarlyBinder<'tcx, ty::Ty<'tcx>>> {
|
||||
desc { |tcx| "computing self type wrt issue #33140 `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
|
||||
|
|
@ -888,7 +888,7 @@ rustc_queries! {
|
|||
}
|
||||
|
||||
/// Computes the signature of the function.
|
||||
query fn_sig(key: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'tcx>> {
|
||||
query fn_sig(key: DefId) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> {
|
||||
desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) }
|
||||
cache_on_disk_if { key.is_local() }
|
||||
separate_provide_extern
|
||||
|
|
|
|||
|
|
@ -752,7 +752,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx UnordSet<LocalDefId>
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
|
||||
for &'tcx UnordMap<DefId, ty::EarlyBinder<Ty<'tcx>>>
|
||||
for &'tcx UnordMap<DefId, ty::EarlyBinder<'tcx, Ty<'tcx>>>
|
||||
{
|
||||
#[inline]
|
||||
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ impl From<ErrorGuaranteed> for NotConstEvaluatable {
|
|||
|
||||
TrivialTypeTraversalImpls! { NotConstEvaluatable }
|
||||
|
||||
pub type BoundAbstractConst<'tcx> = Result<Option<EarlyBinder<ty::Const<'tcx>>>, ErrorGuaranteed>;
|
||||
pub type BoundAbstractConst<'tcx> =
|
||||
Result<Option<EarlyBinder<'tcx, ty::Const<'tcx>>>, ErrorGuaranteed>;
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
pub fn expand_abstract_consts<T: TypeFoldable<TyCtxt<'tcx>>>(self, ac: T) -> T {
|
||||
|
|
|
|||
|
|
@ -579,7 +579,7 @@ impl<'tcx> AdtDef<'tcx> {
|
|||
|
||||
/// Returns a type such that `Self: Sized` if and only if that type is `Sized`,
|
||||
/// or `None` if the type is always sized.
|
||||
pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> Option<ty::EarlyBinder<Ty<'tcx>>> {
|
||||
pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
|
||||
if self.is_struct() { tcx.adt_sized_constraint(self.did()) } else { None }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -184,6 +184,15 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
|
|||
Const::new_var(tcx, vid, ty)
|
||||
}
|
||||
|
||||
fn new_bound(
|
||||
interner: TyCtxt<'tcx>,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
var: ty::BoundVar,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Self {
|
||||
Const::new_bound(interner, debruijn, var, ty)
|
||||
}
|
||||
|
||||
fn new_anon_bound(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
|
|
@ -486,7 +495,10 @@ impl<'tcx> Const<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn const_param_default(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Const<'_>> {
|
||||
pub fn const_param_default<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
|
||||
let default_def_id = match tcx.hir_node_by_def_id(def_id) {
|
||||
hir::Node::GenericParam(hir::GenericParam {
|
||||
kind: hir::GenericParamKind::Const { default: Some(ac), .. },
|
||||
|
|
|
|||
|
|
@ -149,8 +149,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
self.generics_of(def_id)
|
||||
}
|
||||
|
||||
fn type_of_instantiated(self, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> Ty<'tcx> {
|
||||
self.type_of(def_id).instantiate(self, args)
|
||||
fn type_of(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
|
||||
self.type_of(def_id)
|
||||
}
|
||||
|
||||
fn alias_ty_kind(self, alias: ty::AliasTy<'tcx>) -> ty::AliasTyKind {
|
||||
|
|
@ -679,7 +679,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// In order to break cycles involving `AnonConst`, we need to set the expected type by side
|
||||
/// effect. However, we do not want this as a general capability, so this interface restricts
|
||||
/// to the only allowed case.
|
||||
pub fn feed_anon_const_type(self, key: LocalDefId, value: ty::EarlyBinder<Ty<'tcx>>) {
|
||||
pub fn feed_anon_const_type(self, key: LocalDefId, value: ty::EarlyBinder<'tcx, Ty<'tcx>>) {
|
||||
debug_assert_eq!(self.def_kind(key), DefKind::AnonConst);
|
||||
TyCtxtFeed { tcx: self, key }.type_of(value)
|
||||
}
|
||||
|
|
@ -2741,7 +2741,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
pub fn impl_trait_ref(
|
||||
self,
|
||||
def_id: impl IntoQueryParam<DefId>,
|
||||
) -> Option<ty::EarlyBinder<ty::TraitRef<'tcx>>> {
|
||||
) -> Option<ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>> {
|
||||
Some(self.impl_trait_header(def_id)?.trait_ref)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ use rustc_data_structures::fx::FxIndexMap;
|
|||
use rustc_hir::def_id::DefId;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
pub use rustc_type_ir::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
pub use rustc_type_ir::fold::{
|
||||
shift_region, shift_vars, FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Some sample folders
|
||||
|
|
@ -412,103 +414,3 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
Binder::bind_with_vars(inner, bound_vars)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Shifter
|
||||
//
|
||||
// Shifts the De Bruijn indices on all escaping bound vars by a
|
||||
// fixed amount. Useful in instantiation or when otherwise introducing
|
||||
// a binding level that is not intended to capture the existing bound
|
||||
// vars. See comment on `shift_vars_through_binders` method in
|
||||
// `rustc_middle/src/ty/generic_args.rs` for more details.
|
||||
|
||||
struct Shifter<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
current_index: ty::DebruijnIndex,
|
||||
amount: u32,
|
||||
}
|
||||
|
||||
impl<'tcx> Shifter<'tcx> {
|
||||
pub fn new(tcx: TyCtxt<'tcx>, amount: u32) -> Self {
|
||||
Shifter { tcx, current_index: ty::INNERMOST, amount }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Shifter<'tcx> {
|
||||
fn interner(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
|
||||
&mut self,
|
||||
t: ty::Binder<'tcx, T>,
|
||||
) -> ty::Binder<'tcx, T> {
|
||||
self.current_index.shift_in(1);
|
||||
let t = t.super_fold_with(self);
|
||||
self.current_index.shift_out(1);
|
||||
t
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
match *r {
|
||||
ty::ReBound(debruijn, br) if debruijn >= self.current_index => {
|
||||
let debruijn = debruijn.shifted_in(self.amount);
|
||||
ty::Region::new_bound(self.tcx, debruijn, br)
|
||||
}
|
||||
_ => r,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match *ty.kind() {
|
||||
ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => {
|
||||
let debruijn = debruijn.shifted_in(self.amount);
|
||||
Ty::new_bound(self.tcx, debruijn, bound_ty)
|
||||
}
|
||||
|
||||
_ if ty.has_vars_bound_at_or_above(self.current_index) => ty.super_fold_with(self),
|
||||
_ => ty,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
if let ty::ConstKind::Bound(debruijn, bound_ct) = ct.kind()
|
||||
&& debruijn >= self.current_index
|
||||
{
|
||||
let debruijn = debruijn.shifted_in(self.amount);
|
||||
ty::Const::new_bound(self.tcx, debruijn, bound_ct, ct.ty())
|
||||
} else {
|
||||
ct.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
|
||||
if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shift_region<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
region: ty::Region<'tcx>,
|
||||
amount: u32,
|
||||
) -> ty::Region<'tcx> {
|
||||
match *region {
|
||||
ty::ReBound(debruijn, br) if amount > 0 => {
|
||||
ty::Region::new_bound(tcx, debruijn.shifted_in(amount), br)
|
||||
}
|
||||
_ => region,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shift_vars<'tcx, T>(tcx: TyCtxt<'tcx>, value: T, amount: u32) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
debug!("shift_vars(value={:?}, amount={})", value, amount);
|
||||
|
||||
if amount == 0 || !value.has_escaping_bound_vars() {
|
||||
return value;
|
||||
}
|
||||
|
||||
value.fold_with(&mut Shifter::new(tcx, amount))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
// Generic arguments.
|
||||
|
||||
use crate::ty::codec::{TyDecoder, TyEncoder};
|
||||
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
|
||||
use crate::ty::sty::{ClosureArgs, CoroutineArgs, CoroutineClosureArgs, InlineConstArgs};
|
||||
use crate::ty::visit::{TypeVisitable, TypeVisitableExt, TypeVisitor};
|
||||
use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
|
||||
use crate::ty::visit::{TypeVisitable, TypeVisitor};
|
||||
use crate::ty::{self, Lift, List, Ty, TyCtxt};
|
||||
|
||||
use rustc_ast_ir::visit::VisitorResult;
|
||||
use rustc_ast_ir::walk_visitable_list;
|
||||
|
|
@ -12,19 +12,15 @@ use rustc_data_structures::intern::Interned;
|
|||
use rustc_errors::{DiagArgValue, IntoDiagArg};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_macros::extension;
|
||||
use rustc_macros::{
|
||||
Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable,
|
||||
};
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
|
||||
use rustc_serialize::{Decodable, Encodable};
|
||||
use rustc_type_ir::WithCachedTypeInfo;
|
||||
use smallvec::SmallVec;
|
||||
use tracing::debug;
|
||||
|
||||
use core::intrinsics;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use std::num::NonZero;
|
||||
use std::ops::Deref;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
pub type GenericArgKind<'tcx> = rustc_type_ir::GenericArgKind<TyCtxt<'tcx>>;
|
||||
|
|
@ -576,490 +572,6 @@ impl<'tcx, T: TypeVisitable<TyCtxt<'tcx>>> TypeVisitable<TyCtxt<'tcx>> for &'tcx
|
|||
}
|
||||
}
|
||||
|
||||
/// Similar to [`super::Binder`] except that it tracks early bound generics, i.e. `struct Foo<T>(T)`
|
||||
/// needs `T` instantiated immediately. This type primarily exists to avoid forgetting to call
|
||||
/// `instantiate`.
|
||||
///
|
||||
/// If you don't have anything to `instantiate`, you may be looking for
|
||||
/// [`instantiate_identity`](EarlyBinder::instantiate_identity) or [`skip_binder`](EarlyBinder::skip_binder).
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
#[derive(Encodable, Decodable, HashStable)]
|
||||
pub struct EarlyBinder<T> {
|
||||
value: T,
|
||||
}
|
||||
|
||||
/// For early binders, you should first call `instantiate` before using any visitors.
|
||||
impl<'tcx, T> !TypeFoldable<TyCtxt<'tcx>> for ty::EarlyBinder<T> {}
|
||||
impl<'tcx, T> !TypeVisitable<TyCtxt<'tcx>> for ty::EarlyBinder<T> {}
|
||||
|
||||
impl<T> EarlyBinder<T> {
|
||||
pub fn bind(value: T) -> EarlyBinder<T> {
|
||||
EarlyBinder { value }
|
||||
}
|
||||
|
||||
pub fn as_ref(&self) -> EarlyBinder<&T> {
|
||||
EarlyBinder { value: &self.value }
|
||||
}
|
||||
|
||||
pub fn map_bound_ref<F, U>(&self, f: F) -> EarlyBinder<U>
|
||||
where
|
||||
F: FnOnce(&T) -> U,
|
||||
{
|
||||
self.as_ref().map_bound(f)
|
||||
}
|
||||
|
||||
pub fn map_bound<F, U>(self, f: F) -> EarlyBinder<U>
|
||||
where
|
||||
F: FnOnce(T) -> U,
|
||||
{
|
||||
let value = f(self.value);
|
||||
EarlyBinder { value }
|
||||
}
|
||||
|
||||
pub fn try_map_bound<F, U, E>(self, f: F) -> Result<EarlyBinder<U>, E>
|
||||
where
|
||||
F: FnOnce(T) -> Result<U, E>,
|
||||
{
|
||||
let value = f(self.value)?;
|
||||
Ok(EarlyBinder { value })
|
||||
}
|
||||
|
||||
pub fn rebind<U>(&self, value: U) -> EarlyBinder<U> {
|
||||
EarlyBinder { value }
|
||||
}
|
||||
|
||||
/// Skips the binder and returns the "bound" value.
|
||||
/// This can be used to extract data that does not depend on generic parameters
|
||||
/// (e.g., getting the `DefId` of the inner value or getting the number of
|
||||
/// arguments of an `FnSig`). Otherwise, consider using
|
||||
/// [`instantiate_identity`](EarlyBinder::instantiate_identity).
|
||||
///
|
||||
/// To skip the binder on `x: &EarlyBinder<T>` to obtain `&T`, leverage
|
||||
/// [`EarlyBinder::as_ref`](EarlyBinder::as_ref): `x.as_ref().skip_binder()`.
|
||||
///
|
||||
/// See also [`Binder::skip_binder`](super::Binder::skip_binder), which is
|
||||
/// the analogous operation on [`super::Binder`].
|
||||
pub fn skip_binder(self) -> T {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> EarlyBinder<Option<T>> {
|
||||
pub fn transpose(self) -> Option<EarlyBinder<T>> {
|
||||
self.value.map(|value| EarlyBinder { value })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, 's, I: IntoIterator> EarlyBinder<I>
|
||||
where
|
||||
I::Item: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
pub fn iter_instantiated(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
args: &'s [GenericArg<'tcx>],
|
||||
) -> IterInstantiated<'s, 'tcx, I> {
|
||||
IterInstantiated { it: self.value.into_iter(), tcx, args }
|
||||
}
|
||||
|
||||
/// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity),
|
||||
/// but on an iterator of `TypeFoldable` values.
|
||||
pub fn instantiate_identity_iter(self) -> I::IntoIter {
|
||||
self.value.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IterInstantiated<'s, 'tcx, I: IntoIterator> {
|
||||
it: I::IntoIter,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
args: &'s [GenericArg<'tcx>],
|
||||
}
|
||||
|
||||
impl<'tcx, I: IntoIterator> Iterator for IterInstantiated<'_, 'tcx, I>
|
||||
where
|
||||
I::Item: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
type Item = I::Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
Some(EarlyBinder { value: self.it.next()? }.instantiate(self.tcx, self.args))
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.it.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, I: IntoIterator> DoubleEndedIterator for IterInstantiated<'_, 'tcx, I>
|
||||
where
|
||||
I::IntoIter: DoubleEndedIterator,
|
||||
I::Item: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
Some(EarlyBinder { value: self.it.next_back()? }.instantiate(self.tcx, self.args))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, I: IntoIterator> ExactSizeIterator for IterInstantiated<'_, 'tcx, I>
|
||||
where
|
||||
I::IntoIter: ExactSizeIterator,
|
||||
I::Item: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
}
|
||||
|
||||
impl<'tcx, 's, I: IntoIterator> EarlyBinder<I>
|
||||
where
|
||||
I::Item: Deref,
|
||||
<I::Item as Deref>::Target: Copy + TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
pub fn iter_instantiated_copied(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
args: &'s [GenericArg<'tcx>],
|
||||
) -> IterInstantiatedCopied<'s, 'tcx, I> {
|
||||
IterInstantiatedCopied { it: self.value.into_iter(), tcx, args }
|
||||
}
|
||||
|
||||
/// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity),
|
||||
/// but on an iterator of values that deref to a `TypeFoldable`.
|
||||
pub fn instantiate_identity_iter_copied(
|
||||
self,
|
||||
) -> impl Iterator<Item = <I::Item as Deref>::Target> {
|
||||
self.value.into_iter().map(|v| *v)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IterInstantiatedCopied<'a, 'tcx, I: IntoIterator> {
|
||||
it: I::IntoIter,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
args: &'a [GenericArg<'tcx>],
|
||||
}
|
||||
|
||||
impl<'tcx, I: IntoIterator> Iterator for IterInstantiatedCopied<'_, 'tcx, I>
|
||||
where
|
||||
I::Item: Deref,
|
||||
<I::Item as Deref>::Target: Copy + TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
type Item = <I::Item as Deref>::Target;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.it.next().map(|value| EarlyBinder { value: *value }.instantiate(self.tcx, self.args))
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.it.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, I: IntoIterator> DoubleEndedIterator for IterInstantiatedCopied<'_, 'tcx, I>
|
||||
where
|
||||
I::IntoIter: DoubleEndedIterator,
|
||||
I::Item: Deref,
|
||||
<I::Item as Deref>::Target: Copy + TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
self.it
|
||||
.next_back()
|
||||
.map(|value| EarlyBinder { value: *value }.instantiate(self.tcx, self.args))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, I: IntoIterator> ExactSizeIterator for IterInstantiatedCopied<'_, 'tcx, I>
|
||||
where
|
||||
I::IntoIter: ExactSizeIterator,
|
||||
I::Item: Deref,
|
||||
<I::Item as Deref>::Target: Copy + TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
}
|
||||
|
||||
pub struct EarlyBinderIter<T> {
|
||||
t: T,
|
||||
}
|
||||
|
||||
impl<T: IntoIterator> EarlyBinder<T> {
|
||||
pub fn transpose_iter(self) -> EarlyBinderIter<T::IntoIter> {
|
||||
EarlyBinderIter { t: self.value.into_iter() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Iterator> Iterator for EarlyBinderIter<T> {
|
||||
type Item = EarlyBinder<T::Item>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.t.next().map(|value| EarlyBinder { value })
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.t.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> ty::EarlyBinder<T> {
|
||||
pub fn instantiate(self, tcx: TyCtxt<'tcx>, args: &[GenericArg<'tcx>]) -> T {
|
||||
let mut folder = ArgFolder { tcx, args, binders_passed: 0 };
|
||||
self.value.fold_with(&mut folder)
|
||||
}
|
||||
|
||||
/// Makes the identity replacement `T0 => T0, ..., TN => TN`.
|
||||
/// Conceptually, this converts universally bound variables into placeholders
|
||||
/// when inside of a given item.
|
||||
///
|
||||
/// For example, consider `for<T> fn foo<T>(){ .. }`:
|
||||
/// - Outside of `foo`, `T` is bound (represented by the presence of `EarlyBinder`).
|
||||
/// - Inside of the body of `foo`, we treat `T` as a placeholder by calling
|
||||
/// `instantiate_identity` to discharge the `EarlyBinder`.
|
||||
pub fn instantiate_identity(self) -> T {
|
||||
self.value
|
||||
}
|
||||
|
||||
/// Returns the inner value, but only if it contains no bound vars.
|
||||
pub fn no_bound_vars(self) -> Option<T> {
|
||||
if !self.value.has_param() { Some(self.value) } else { None }
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// The actual instantiation engine itself is a type folder.
|
||||
|
||||
struct ArgFolder<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
args: &'a [GenericArg<'tcx>],
|
||||
|
||||
/// Number of region binders we have passed through while doing the instantiation
|
||||
binders_passed: u32,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ArgFolder<'a, 'tcx> {
|
||||
#[inline]
|
||||
fn interner(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
|
||||
&mut self,
|
||||
t: ty::Binder<'tcx, T>,
|
||||
) -> ty::Binder<'tcx, T> {
|
||||
self.binders_passed += 1;
|
||||
let t = t.super_fold_with(self);
|
||||
self.binders_passed -= 1;
|
||||
t
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn region_param_out_of_range(data: ty::EarlyParamRegion, args: &[GenericArg<'_>]) -> ! {
|
||||
bug!(
|
||||
"Region parameter out of range when instantiating in region {} (index={}, args = {:?})",
|
||||
data.name,
|
||||
data.index,
|
||||
args,
|
||||
)
|
||||
}
|
||||
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn region_param_invalid(data: ty::EarlyParamRegion, other: GenericArgKind<'_>) -> ! {
|
||||
bug!(
|
||||
"Unexpected parameter {:?} when instantiating in region {} (index={})",
|
||||
other,
|
||||
data.name,
|
||||
data.index
|
||||
)
|
||||
}
|
||||
|
||||
// Note: This routine only handles regions that are bound on
|
||||
// type declarations and other outer declarations, not those
|
||||
// bound in *fn types*. Region instantiation of the bound
|
||||
// regions that appear in a function signature is done using
|
||||
// the specialized routine `ty::replace_late_regions()`.
|
||||
match *r {
|
||||
ty::ReEarlyParam(data) => {
|
||||
let rk = self.args.get(data.index as usize).map(|k| k.unpack());
|
||||
match rk {
|
||||
Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt),
|
||||
Some(other) => region_param_invalid(data, other),
|
||||
None => region_param_out_of_range(data, self.args),
|
||||
}
|
||||
}
|
||||
ty::ReBound(..)
|
||||
| ty::ReLateParam(_)
|
||||
| ty::ReStatic
|
||||
| ty::RePlaceholder(_)
|
||||
| ty::ReErased
|
||||
| ty::ReError(_) => r,
|
||||
ty::ReVar(_) => bug!("unexpected region: {r:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
if !t.has_param() {
|
||||
return t;
|
||||
}
|
||||
|
||||
match *t.kind() {
|
||||
ty::Param(p) => self.ty_for_param(p, t),
|
||||
_ => t.super_fold_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
if let ty::ConstKind::Param(p) = c.kind() {
|
||||
self.const_for_param(p, c)
|
||||
} else {
|
||||
c.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ArgFolder<'a, 'tcx> {
|
||||
fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
// Look up the type in the args. It really should be in there.
|
||||
let opt_ty = self.args.get(p.index as usize).map(|k| k.unpack());
|
||||
let ty = match opt_ty {
|
||||
Some(GenericArgKind::Type(ty)) => ty,
|
||||
Some(kind) => self.type_param_expected(p, source_ty, kind),
|
||||
None => self.type_param_out_of_range(p, source_ty),
|
||||
};
|
||||
|
||||
self.shift_vars_through_binders(ty)
|
||||
}
|
||||
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn type_param_expected(&self, p: ty::ParamTy, ty: Ty<'tcx>, kind: GenericArgKind<'tcx>) -> ! {
|
||||
bug!(
|
||||
"expected type for `{:?}` ({:?}/{}) but found {:?} when instantiating, args={:?}",
|
||||
p,
|
||||
ty,
|
||||
p.index,
|
||||
kind,
|
||||
self.args,
|
||||
)
|
||||
}
|
||||
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn type_param_out_of_range(&self, p: ty::ParamTy, ty: Ty<'tcx>) -> ! {
|
||||
bug!(
|
||||
"type parameter `{:?}` ({:?}/{}) out of range when instantiating, args={:?}",
|
||||
p,
|
||||
ty,
|
||||
p.index,
|
||||
self.args,
|
||||
)
|
||||
}
|
||||
|
||||
fn const_for_param(&self, p: ParamConst, source_ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
// Look up the const in the args. It really should be in there.
|
||||
let opt_ct = self.args.get(p.index as usize).map(|k| k.unpack());
|
||||
let ct = match opt_ct {
|
||||
Some(GenericArgKind::Const(ct)) => ct,
|
||||
Some(kind) => self.const_param_expected(p, source_ct, kind),
|
||||
None => self.const_param_out_of_range(p, source_ct),
|
||||
};
|
||||
|
||||
self.shift_vars_through_binders(ct)
|
||||
}
|
||||
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn const_param_expected(
|
||||
&self,
|
||||
p: ty::ParamConst,
|
||||
ct: ty::Const<'tcx>,
|
||||
kind: GenericArgKind<'tcx>,
|
||||
) -> ! {
|
||||
bug!(
|
||||
"expected const for `{:?}` ({:?}/{}) but found {:?} when instantiating args={:?}",
|
||||
p,
|
||||
ct,
|
||||
p.index,
|
||||
kind,
|
||||
self.args,
|
||||
)
|
||||
}
|
||||
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn const_param_out_of_range(&self, p: ty::ParamConst, ct: ty::Const<'tcx>) -> ! {
|
||||
bug!(
|
||||
"const parameter `{:?}` ({:?}/{}) out of range when instantiating args={:?}",
|
||||
p,
|
||||
ct,
|
||||
p.index,
|
||||
self.args,
|
||||
)
|
||||
}
|
||||
|
||||
/// It is sometimes necessary to adjust the De Bruijn indices during instantiation. This occurs
|
||||
/// when we are instantating a type with escaping bound vars into a context where we have
|
||||
/// passed through binders. That's quite a mouthful. Let's see an example:
|
||||
///
|
||||
/// ```
|
||||
/// type Func<A> = fn(A);
|
||||
/// type MetaFunc = for<'a> fn(Func<&'a i32>);
|
||||
/// ```
|
||||
///
|
||||
/// The type `MetaFunc`, when fully expanded, will be
|
||||
/// ```ignore (illustrative)
|
||||
/// for<'a> fn(fn(&'a i32))
|
||||
/// // ^~ ^~ ^~~
|
||||
/// // | | |
|
||||
/// // | | DebruijnIndex of 2
|
||||
/// // Binders
|
||||
/// ```
|
||||
/// Here the `'a` lifetime is bound in the outer function, but appears as an argument of the
|
||||
/// inner one. Therefore, that appearance will have a DebruijnIndex of 2, because we must skip
|
||||
/// over the inner binder (remember that we count De Bruijn indices from 1). However, in the
|
||||
/// definition of `MetaFunc`, the binder is not visible, so the type `&'a i32` will have a
|
||||
/// De Bruijn index of 1. It's only during the instantiation that we can see we must increase the
|
||||
/// depth by 1 to account for the binder that we passed through.
|
||||
///
|
||||
/// As a second example, consider this twist:
|
||||
///
|
||||
/// ```
|
||||
/// type FuncTuple<A> = (A,fn(A));
|
||||
/// type MetaFuncTuple = for<'a> fn(FuncTuple<&'a i32>);
|
||||
/// ```
|
||||
///
|
||||
/// Here the final type will be:
|
||||
/// ```ignore (illustrative)
|
||||
/// for<'a> fn((&'a i32, fn(&'a i32)))
|
||||
/// // ^~~ ^~~
|
||||
/// // | |
|
||||
/// // DebruijnIndex of 1 |
|
||||
/// // DebruijnIndex of 2
|
||||
/// ```
|
||||
/// As indicated in the diagram, here the same type `&'a i32` is instantiated once, but in the
|
||||
/// first case we do not increase the De Bruijn index and in the second case we do. The reason
|
||||
/// is that only in the second case have we passed through a fn binder.
|
||||
fn shift_vars_through_binders<T: TypeFoldable<TyCtxt<'tcx>>>(&self, val: T) -> T {
|
||||
debug!(
|
||||
"shift_vars(val={:?}, binders_passed={:?}, has_escaping_bound_vars={:?})",
|
||||
val,
|
||||
self.binders_passed,
|
||||
val.has_escaping_bound_vars()
|
||||
);
|
||||
|
||||
if self.binders_passed == 0 || !val.has_escaping_bound_vars() {
|
||||
return val;
|
||||
}
|
||||
|
||||
let result = ty::fold::shift_vars(TypeFolder::interner(self), val, self.binders_passed);
|
||||
debug!("shift_vars: shifted result = {:?}", result);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn shift_region_through_binders(&self, region: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
if self.binders_passed == 0 || !region.has_escaping_bound_vars() {
|
||||
return region;
|
||||
}
|
||||
ty::fold::shift_region(self.tcx, region, self.binders_passed)
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores the user-given args to reach some fully qualified path
|
||||
/// (e.g., `<T>::Item` or `<T as Trait>::Item`).
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ impl GenericParamDef {
|
|||
pub fn default_value<'tcx>(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Option<EarlyBinder<ty::GenericArg<'tcx>>> {
|
||||
) -> Option<EarlyBinder<'tcx, ty::GenericArg<'tcx>>> {
|
||||
match self.kind {
|
||||
GenericParamDefKind::Type { has_default, .. } if has_default => {
|
||||
Some(tcx.type_of(self.def_id).map_bound(|t| t.into()))
|
||||
|
|
|
|||
|
|
@ -764,7 +764,7 @@ impl<'tcx> Instance<'tcx> {
|
|||
self.def.has_polymorphic_mir_body().then_some(self.args)
|
||||
}
|
||||
|
||||
pub fn instantiate_mir<T>(&self, tcx: TyCtxt<'tcx>, v: EarlyBinder<&T>) -> T
|
||||
pub fn instantiate_mir<T>(&self, tcx: TyCtxt<'tcx>, v: EarlyBinder<'tcx, &T>) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
|
||||
{
|
||||
|
|
@ -782,7 +782,7 @@ impl<'tcx> Instance<'tcx> {
|
|||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
v: EarlyBinder<T>,
|
||||
v: EarlyBinder<'tcx, T>,
|
||||
) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
|
|
@ -800,7 +800,7 @@ impl<'tcx> Instance<'tcx> {
|
|||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
v: EarlyBinder<T>,
|
||||
v: EarlyBinder<'tcx, T>,
|
||||
) -> Result<T, NormalizationError<'tcx>>
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
|
|
|
|||
|
|
@ -114,9 +114,9 @@ pub use self::rvalue_scopes::RvalueScopes;
|
|||
pub use self::sty::{
|
||||
AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig,
|
||||
ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, CoroutineClosureArgs,
|
||||
CoroutineClosureArgsParts, CoroutineClosureSignature, FnSig, GenSig, InlineConstArgs,
|
||||
InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs,
|
||||
VarianceDiagInfo,
|
||||
CoroutineClosureArgsParts, CoroutineClosureSignature, EarlyBinder, FnSig, GenSig,
|
||||
InlineConstArgs, InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut,
|
||||
UpvarArgs, VarianceDiagInfo,
|
||||
};
|
||||
pub use self::trait_def::TraitDef;
|
||||
pub use self::typeck_results::{
|
||||
|
|
@ -266,7 +266,7 @@ pub struct ImplHeader<'tcx> {
|
|||
|
||||
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
pub struct ImplTraitHeader<'tcx> {
|
||||
pub trait_ref: ty::EarlyBinder<ty::TraitRef<'tcx>>,
|
||||
pub trait_ref: ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>,
|
||||
pub polarity: ImplPolarity,
|
||||
pub safety: hir::Safety,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
self,
|
||||
param_args: GenericArgsRef<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
value: EarlyBinder<T>,
|
||||
value: EarlyBinder<'tcx, T>,
|
||||
) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
|
|
@ -143,7 +143,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
self,
|
||||
param_args: GenericArgsRef<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
value: EarlyBinder<T>,
|
||||
value: EarlyBinder<'tcx, T>,
|
||||
) -> Result<T, NormalizationError<'tcx>>
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::Binder<'static, T> {
|
|||
type Value<'tcx> = ty::Binder<'tcx, T::Value<'tcx>>;
|
||||
}
|
||||
|
||||
impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::EarlyBinder<T> {
|
||||
type Value<'tcx> = ty::EarlyBinder<T::Value<'tcx>>;
|
||||
impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::EarlyBinder<'static, T> {
|
||||
type Value<'tcx> = ty::EarlyBinder<'tcx, T::Value<'tcx>>;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
|
|
|||
|
|
@ -138,6 +138,14 @@ impl<'tcx> Region<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::Region<TyCtxt<'tcx>> for Region<'tcx> {
|
||||
fn new_bound(
|
||||
interner: TyCtxt<'tcx>,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
var: ty::BoundRegion,
|
||||
) -> Self {
|
||||
Region::new_bound(interner, debruijn, var)
|
||||
}
|
||||
|
||||
fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
|
||||
Region::new_bound(tcx, debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::BrAnon })
|
||||
}
|
||||
|
|
@ -327,6 +335,12 @@ pub struct EarlyParamRegion {
|
|||
pub name: Symbol,
|
||||
}
|
||||
|
||||
impl rustc_type_ir::inherent::ParamLike for EarlyParamRegion {
|
||||
fn index(self) -> u32 {
|
||||
self.index
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for EarlyParamRegion {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}/#{}", self.name, self.index)
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ pub type TypeAndMut<'tcx> = ir::TypeAndMut<TyCtxt<'tcx>>;
|
|||
pub type AliasTy<'tcx> = ir::AliasTy<TyCtxt<'tcx>>;
|
||||
pub type FnSig<'tcx> = ir::FnSig<TyCtxt<'tcx>>;
|
||||
pub type Binder<'tcx, T> = ir::Binder<TyCtxt<'tcx>, T>;
|
||||
pub type EarlyBinder<'tcx, T> = ir::EarlyBinder<TyCtxt<'tcx>, T>;
|
||||
|
||||
pub trait Article {
|
||||
fn article(&self) -> &'static str;
|
||||
|
|
@ -954,6 +955,12 @@ pub struct ParamTy {
|
|||
pub name: Symbol,
|
||||
}
|
||||
|
||||
impl rustc_type_ir::inherent::ParamLike for ParamTy {
|
||||
fn index(self) -> u32 {
|
||||
self.index
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ParamTy {
|
||||
pub fn new(index: u32, name: Symbol) -> ParamTy {
|
||||
ParamTy { index, name }
|
||||
|
|
@ -982,6 +989,12 @@ pub struct ParamConst {
|
|||
pub name: Symbol,
|
||||
}
|
||||
|
||||
impl rustc_type_ir::inherent::ParamLike for ParamConst {
|
||||
fn index(self) -> u32 {
|
||||
self.index
|
||||
}
|
||||
}
|
||||
|
||||
impl ParamConst {
|
||||
pub fn new(index: u32, name: Symbol) -> ParamConst {
|
||||
ParamConst { index, name }
|
||||
|
|
@ -1423,6 +1436,10 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
|
|||
Ty::new_var(tcx, vid)
|
||||
}
|
||||
|
||||
fn new_bound(interner: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundTy) -> Self {
|
||||
Ty::new_bound(interner, debruijn, var)
|
||||
}
|
||||
|
||||
fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
|
||||
Ty::new_bound(tcx, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon })
|
||||
}
|
||||
|
|
@ -2055,7 +2072,7 @@ impl<'tcx> Ty<'tcx> {
|
|||
fn async_destructor_combinator(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
lang_item: LangItem,
|
||||
) -> ty::EarlyBinder<Ty<'tcx>> {
|
||||
) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
|
||||
tcx.fn_sig(tcx.require_lang_item(lang_item, None))
|
||||
.map_bound(|fn_sig| fn_sig.output().no_bound_vars().unwrap())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -694,7 +694,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
pub fn coroutine_hidden_types(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> impl Iterator<Item = ty::EarlyBinder<Ty<'tcx>>> {
|
||||
) -> impl Iterator<Item = ty::EarlyBinder<'tcx, Ty<'tcx>>> {
|
||||
let coroutine_layout = self.mir_coroutine_witnesses(def_id);
|
||||
coroutine_layout
|
||||
.as_ref()
|
||||
|
|
@ -709,7 +709,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
pub fn bound_coroutine_hidden_types(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> impl Iterator<Item = ty::EarlyBinder<ty::Binder<'tcx, Ty<'tcx>>>> {
|
||||
) -> impl Iterator<Item = ty::EarlyBinder<'tcx, ty::Binder<'tcx, Ty<'tcx>>>> {
|
||||
let coroutine_layout = self.mir_coroutine_witnesses(def_id);
|
||||
coroutine_layout
|
||||
.as_ref()
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Value<TyCtxt<'tcx>> for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
|
||||
impl<'tcx> Value<TyCtxt<'tcx>> for Result<ty::EarlyBinder<'_, Ty<'_>>, CyclePlaceholder> {
|
||||
fn from_cycle_error(_tcx: TyCtxt<'tcx>, _: &CycleError, guar: ErrorGuaranteed) -> Self {
|
||||
Err(CyclePlaceholder(guar))
|
||||
}
|
||||
|
|
@ -111,7 +111,7 @@ impl<'tcx> Value<TyCtxt<'tcx>> for Representability {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<Ty<'_>> {
|
||||
impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<'_, Ty<'_>> {
|
||||
fn from_cycle_error(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
cycle_error: &CycleError,
|
||||
|
|
@ -121,7 +121,7 @@ impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<Ty<'_>> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> {
|
||||
impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<'_, ty::Binder<'_, ty::FnSig<'_>>> {
|
||||
fn from_cycle_error(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
cycle_error: &CycleError,
|
||||
|
|
|
|||
|
|
@ -689,8 +689,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
if Some(adt_def.did()) == self.tcx.lang_items().dyn_metadata() {
|
||||
self.fail(
|
||||
location,
|
||||
format!("You can't project to field {f:?} of `DynMetadata` because \
|
||||
layout is weird and thinks it doesn't have fields."),
|
||||
format!(
|
||||
"You can't project to field {f:?} of `DynMetadata` because \
|
||||
layout is weird and thinks it doesn't have fields."
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -839,7 +841,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
&& cntxt != PlaceContext::NonUse(NonUseContext::VarDebugInfo)
|
||||
&& place.projection[1..].contains(&ProjectionElem::Deref)
|
||||
{
|
||||
self.fail(location, format!("{place:?}, has deref at the wrong place"));
|
||||
self.fail(
|
||||
location,
|
||||
format!("place {place:?} has deref as a later projection (it is only permitted as the first projection)"),
|
||||
);
|
||||
}
|
||||
|
||||
// Ensure all downcast projections are followed by field projections.
|
||||
let mut projections_iter = place.projection.iter();
|
||||
while let Some(proj) = projections_iter.next() {
|
||||
if matches!(proj, ProjectionElem::Downcast(..)) {
|
||||
if !matches!(projections_iter.next(), Some(ProjectionElem::Field(..))) {
|
||||
self.fail(
|
||||
location,
|
||||
format!(
|
||||
"place {place:?} has `Downcast` projection not followed by `Field`"
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.super_place(place, cntxt, location);
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, S, V> Stable<'tcx> for ty::EarlyBinder<S>
|
||||
impl<'tcx, S, V> Stable<'tcx> for ty::EarlyBinder<'tcx, S>
|
||||
where
|
||||
S: Stable<'tcx, T = V>,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -99,6 +99,13 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
|||
previous call to `try_evaluate_added_goals!`"
|
||||
);
|
||||
|
||||
// We only check for leaks from universes which were entered inside
|
||||
// of the query.
|
||||
self.infcx.leak_check(self.max_input_universe, None).map_err(|e| {
|
||||
trace!(?e, "failed the leak check");
|
||||
NoSolution
|
||||
})?;
|
||||
|
||||
// When normalizing, we've replaced the expected term with an unconstrained
|
||||
// inference variable. This means that we dropped information which could
|
||||
// have been important. We handle this by instead returning the nested goals
|
||||
|
|
@ -121,7 +128,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
|||
};
|
||||
|
||||
let external_constraints =
|
||||
self.compute_external_query_constraints(normalization_nested_goals)?;
|
||||
self.compute_external_query_constraints(certainty, normalization_nested_goals);
|
||||
let (var_values, mut external_constraints) =
|
||||
(self.var_values, external_constraints).fold_with(&mut EagerResolver::new(self.infcx));
|
||||
// Remove any trivial region constraints once we've resolved regions
|
||||
|
|
@ -170,30 +177,37 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
|||
#[instrument(level = "trace", skip(self), ret)]
|
||||
fn compute_external_query_constraints(
|
||||
&self,
|
||||
certainty: Certainty,
|
||||
normalization_nested_goals: NestedNormalizationGoals<'tcx>,
|
||||
) -> Result<ExternalConstraintsData<'tcx>, NoSolution> {
|
||||
// We only check for leaks from universes which were entered inside
|
||||
// of the query.
|
||||
self.infcx.leak_check(self.max_input_universe, None).map_err(|e| {
|
||||
trace!(?e, "failed the leak check");
|
||||
NoSolution
|
||||
})?;
|
||||
) -> ExternalConstraintsData<'tcx> {
|
||||
// We only return region constraints once the certainty is `Yes`. This
|
||||
// is necessary as we may drop nested goals on ambiguity, which may result
|
||||
// in unconstrained inference variables in the region constraints. It also
|
||||
// prevents us from emitting duplicate region constraints, avoiding some
|
||||
// unnecessary work. This slightly weakens the leak check in case it uses
|
||||
// region constraints from an ambiguous nested goal. This is tested in both
|
||||
// `tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs` and
|
||||
// `tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs`.
|
||||
let region_constraints = if certainty == Certainty::Yes {
|
||||
// Cannot use `take_registered_region_obligations` as we may compute the response
|
||||
// inside of a `probe` whenever we have multiple choices inside of the solver.
|
||||
let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned();
|
||||
let mut region_constraints = self.infcx.with_region_constraints(|region_constraints| {
|
||||
make_query_region_constraints(
|
||||
self.tcx(),
|
||||
region_obligations.iter().map(|r_o| {
|
||||
(r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())
|
||||
}),
|
||||
region_constraints,
|
||||
)
|
||||
});
|
||||
|
||||
// Cannot use `take_registered_region_obligations` as we may compute the response
|
||||
// inside of a `probe` whenever we have multiple choices inside of the solver.
|
||||
let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned();
|
||||
let mut region_constraints = self.infcx.with_region_constraints(|region_constraints| {
|
||||
make_query_region_constraints(
|
||||
self.tcx(),
|
||||
region_obligations
|
||||
.iter()
|
||||
.map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())),
|
||||
region_constraints,
|
||||
)
|
||||
});
|
||||
|
||||
let mut seen = FxHashSet::default();
|
||||
region_constraints.outlives.retain(|outlives| seen.insert(*outlives));
|
||||
let mut seen = FxHashSet::default();
|
||||
region_constraints.outlives.retain(|outlives| seen.insert(*outlives));
|
||||
region_constraints
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
|
||||
let mut opaque_types = self.infcx.clone_opaque_types_for_query_response();
|
||||
// Only return opaque type keys for newly-defined opaques
|
||||
|
|
@ -201,7 +215,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
|||
self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a)
|
||||
});
|
||||
|
||||
Ok(ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals })
|
||||
ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals }
|
||||
}
|
||||
|
||||
/// After calling a canonical query, we apply the constraints returned
|
||||
|
|
|
|||
|
|
@ -2097,7 +2097,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
|
|||
let args = translate_args(selcx.infcx, param_env, impl_def_id, args, assoc_ty.defining_node);
|
||||
let ty = tcx.type_of(assoc_ty.item.def_id);
|
||||
let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst);
|
||||
let term: ty::EarlyBinder<ty::Term<'tcx>> = if is_const {
|
||||
let term: ty::EarlyBinder<'tcx, ty::Term<'tcx>> = if is_const {
|
||||
let did = assoc_ty.item.def_id;
|
||||
let identity_args = crate::traits::GenericArgs::identity_for_item(tcx, did);
|
||||
let uv = ty::UnevaluatedConst::new(did, identity_args);
|
||||
|
|
|
|||
|
|
@ -398,10 +398,10 @@ impl<'a, 'tcx> visit::Visitor<'a, 'tcx> for IsThirPolymorphic<'a, 'tcx> {
|
|||
}
|
||||
|
||||
/// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead.
|
||||
fn thir_abstract_const(
|
||||
tcx: TyCtxt<'_>,
|
||||
fn thir_abstract_const<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def: LocalDefId,
|
||||
) -> Result<Option<ty::EarlyBinder<ty::Const<'_>>>, ErrorGuaranteed> {
|
||||
) -> Result<Option<ty::EarlyBinder<'tcx, ty::Const<'tcx>>>, ErrorGuaranteed> {
|
||||
if !tcx.features().generic_const_exprs {
|
||||
return Ok(None);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness {
|
|||
fn adt_sized_constraint<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
) -> Option<ty::EarlyBinder<Ty<'tcx>>> {
|
||||
) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
|
||||
if let Some(def_id) = def_id.as_local() {
|
||||
if let ty::Representability::Infinite(_) = tcx.representability(def_id) {
|
||||
return None;
|
||||
|
|
@ -253,7 +253,7 @@ fn param_env_reveal_all_normalized(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamE
|
|||
fn self_ty_of_trait_impl_enabling_order_dep_trait_object_hack(
|
||||
tcx: TyCtxt<'_>,
|
||||
def_id: DefId,
|
||||
) -> Option<EarlyBinder<Ty<'_>>> {
|
||||
) -> Option<EarlyBinder<'_, Ty<'_>>> {
|
||||
let impl_ =
|
||||
tcx.impl_trait_header(def_id).unwrap_or_else(|| bug!("called on inherent impl {def_id:?}"));
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ rustc_serialize = { path = "../rustc_serialize", optional = true }
|
|||
rustc_span = { path = "../rustc_span", optional = true }
|
||||
rustc_type_ir_macros = { path = "../rustc_type_ir_macros" }
|
||||
smallvec = { version = "1.8.1", default-features = false }
|
||||
tracing = "0.1"
|
||||
# tidy-alphabetical-end
|
||||
|
||||
[features]
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{ControlFlow, Deref};
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_macros::HashStable_NoContext;
|
||||
use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
|
||||
use rustc_serialize::Decodable;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
|
||||
use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
use crate::inherent::*;
|
||||
use crate::lift::Lift;
|
||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
|
||||
|
|
@ -338,3 +340,516 @@ impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> {
|
|||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Similar to [`super::Binder`] except that it tracks early bound generics, i.e. `struct Foo<T>(T)`
|
||||
/// needs `T` instantiated immediately. This type primarily exists to avoid forgetting to call
|
||||
/// `instantiate`.
|
||||
///
|
||||
/// If you don't have anything to `instantiate`, you may be looking for
|
||||
/// [`instantiate_identity`](EarlyBinder::instantiate_identity) or [`skip_binder`](EarlyBinder::skip_binder).
|
||||
#[derive(derivative::Derivative)]
|
||||
#[derivative(
|
||||
Clone(bound = "T: Clone"),
|
||||
Copy(bound = "T: Copy"),
|
||||
PartialEq(bound = "T: PartialEq"),
|
||||
Eq(bound = "T: Eq"),
|
||||
Ord(bound = "T: Ord"),
|
||||
PartialOrd(bound = "T: Ord"),
|
||||
Hash(bound = "T: Hash"),
|
||||
Debug(bound = "T: Debug")
|
||||
)]
|
||||
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
|
||||
pub struct EarlyBinder<I: Interner, T> {
|
||||
value: T,
|
||||
_tcx: PhantomData<I>,
|
||||
}
|
||||
|
||||
/// For early binders, you should first call `instantiate` before using any visitors.
|
||||
#[cfg(feature = "nightly")]
|
||||
impl<I: Interner, T> !TypeFoldable<I> for ty::EarlyBinder<I, T> {}
|
||||
|
||||
/// For early binders, you should first call `instantiate` before using any visitors.
|
||||
#[cfg(feature = "nightly")]
|
||||
impl<I: Interner, T> !TypeVisitable<I> for ty::EarlyBinder<I, T> {}
|
||||
|
||||
impl<I: Interner, T> EarlyBinder<I, T> {
|
||||
pub fn bind(value: T) -> EarlyBinder<I, T> {
|
||||
EarlyBinder { value, _tcx: PhantomData }
|
||||
}
|
||||
|
||||
pub fn as_ref(&self) -> EarlyBinder<I, &T> {
|
||||
EarlyBinder { value: &self.value, _tcx: PhantomData }
|
||||
}
|
||||
|
||||
pub fn map_bound_ref<F, U>(&self, f: F) -> EarlyBinder<I, U>
|
||||
where
|
||||
F: FnOnce(&T) -> U,
|
||||
{
|
||||
self.as_ref().map_bound(f)
|
||||
}
|
||||
|
||||
pub fn map_bound<F, U>(self, f: F) -> EarlyBinder<I, U>
|
||||
where
|
||||
F: FnOnce(T) -> U,
|
||||
{
|
||||
let value = f(self.value);
|
||||
EarlyBinder { value, _tcx: PhantomData }
|
||||
}
|
||||
|
||||
pub fn try_map_bound<F, U, E>(self, f: F) -> Result<EarlyBinder<I, U>, E>
|
||||
where
|
||||
F: FnOnce(T) -> Result<U, E>,
|
||||
{
|
||||
let value = f(self.value)?;
|
||||
Ok(EarlyBinder { value, _tcx: PhantomData })
|
||||
}
|
||||
|
||||
pub fn rebind<U>(&self, value: U) -> EarlyBinder<I, U> {
|
||||
EarlyBinder { value, _tcx: PhantomData }
|
||||
}
|
||||
|
||||
/// Skips the binder and returns the "bound" value.
|
||||
/// This can be used to extract data that does not depend on generic parameters
|
||||
/// (e.g., getting the `DefId` of the inner value or getting the number of
|
||||
/// arguments of an `FnSig`). Otherwise, consider using
|
||||
/// [`instantiate_identity`](EarlyBinder::instantiate_identity).
|
||||
///
|
||||
/// To skip the binder on `x: &EarlyBinder<I, T>` to obtain `&T`, leverage
|
||||
/// [`EarlyBinder::as_ref`](EarlyBinder::as_ref): `x.as_ref().skip_binder()`.
|
||||
///
|
||||
/// See also [`Binder::skip_binder`](super::Binder::skip_binder), which is
|
||||
/// the analogous operation on [`super::Binder`].
|
||||
pub fn skip_binder(self) -> T {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, T> EarlyBinder<I, Option<T>> {
|
||||
pub fn transpose(self) -> Option<EarlyBinder<I, T>> {
|
||||
self.value.map(|value| EarlyBinder { value, _tcx: PhantomData })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, I: Interner, Iter: IntoIterator> EarlyBinder<I, Iter>
|
||||
where
|
||||
Iter::Item: TypeFoldable<I>,
|
||||
{
|
||||
pub fn iter_instantiated(
|
||||
self,
|
||||
tcx: I,
|
||||
args: &'s [I::GenericArg],
|
||||
) -> IterInstantiated<'s, I, Iter> {
|
||||
IterInstantiated { it: self.value.into_iter(), tcx, args }
|
||||
}
|
||||
|
||||
/// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity),
|
||||
/// but on an iterator of `TypeFoldable` values.
|
||||
pub fn instantiate_identity_iter(self) -> Iter::IntoIter {
|
||||
self.value.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IterInstantiated<'s, I: Interner, Iter: IntoIterator> {
|
||||
it: Iter::IntoIter,
|
||||
tcx: I,
|
||||
args: &'s [I::GenericArg],
|
||||
}
|
||||
|
||||
impl<I: Interner, Iter: IntoIterator> Iterator for IterInstantiated<'_, I, Iter>
|
||||
where
|
||||
Iter::Item: TypeFoldable<I>,
|
||||
{
|
||||
type Item = Iter::Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
Some(
|
||||
EarlyBinder { value: self.it.next()?, _tcx: PhantomData }
|
||||
.instantiate(self.tcx, self.args),
|
||||
)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.it.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, Iter: IntoIterator> DoubleEndedIterator for IterInstantiated<'_, I, Iter>
|
||||
where
|
||||
Iter::IntoIter: DoubleEndedIterator,
|
||||
Iter::Item: TypeFoldable<I>,
|
||||
{
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
Some(
|
||||
EarlyBinder { value: self.it.next_back()?, _tcx: PhantomData }
|
||||
.instantiate(self.tcx, self.args),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, Iter: IntoIterator> ExactSizeIterator for IterInstantiated<'_, I, Iter>
|
||||
where
|
||||
Iter::IntoIter: ExactSizeIterator,
|
||||
Iter::Item: TypeFoldable<I>,
|
||||
{
|
||||
}
|
||||
|
||||
impl<'s, I: Interner, Iter: IntoIterator> EarlyBinder<I, Iter>
|
||||
where
|
||||
Iter::Item: Deref,
|
||||
<Iter::Item as Deref>::Target: Copy + TypeFoldable<I>,
|
||||
{
|
||||
pub fn iter_instantiated_copied(
|
||||
self,
|
||||
tcx: I,
|
||||
args: &'s [I::GenericArg],
|
||||
) -> IterInstantiatedCopied<'s, I, Iter> {
|
||||
IterInstantiatedCopied { it: self.value.into_iter(), tcx, args }
|
||||
}
|
||||
|
||||
/// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity),
|
||||
/// but on an iterator of values that deref to a `TypeFoldable`.
|
||||
pub fn instantiate_identity_iter_copied(
|
||||
self,
|
||||
) -> impl Iterator<Item = <Iter::Item as Deref>::Target> {
|
||||
self.value.into_iter().map(|v| *v)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IterInstantiatedCopied<'a, I: Interner, Iter: IntoIterator> {
|
||||
it: Iter::IntoIter,
|
||||
tcx: I,
|
||||
args: &'a [I::GenericArg],
|
||||
}
|
||||
|
||||
impl<I: Interner, Iter: IntoIterator> Iterator for IterInstantiatedCopied<'_, I, Iter>
|
||||
where
|
||||
Iter::Item: Deref,
|
||||
<Iter::Item as Deref>::Target: Copy + TypeFoldable<I>,
|
||||
{
|
||||
type Item = <Iter::Item as Deref>::Target;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.it.next().map(|value| {
|
||||
EarlyBinder { value: *value, _tcx: PhantomData }.instantiate(self.tcx, self.args)
|
||||
})
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.it.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, Iter: IntoIterator> DoubleEndedIterator for IterInstantiatedCopied<'_, I, Iter>
|
||||
where
|
||||
Iter::IntoIter: DoubleEndedIterator,
|
||||
Iter::Item: Deref,
|
||||
<Iter::Item as Deref>::Target: Copy + TypeFoldable<I>,
|
||||
{
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
self.it.next_back().map(|value| {
|
||||
EarlyBinder { value: *value, _tcx: PhantomData }.instantiate(self.tcx, self.args)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, Iter: IntoIterator> ExactSizeIterator for IterInstantiatedCopied<'_, I, Iter>
|
||||
where
|
||||
Iter::IntoIter: ExactSizeIterator,
|
||||
Iter::Item: Deref,
|
||||
<Iter::Item as Deref>::Target: Copy + TypeFoldable<I>,
|
||||
{
|
||||
}
|
||||
|
||||
pub struct EarlyBinderIter<I, T> {
|
||||
t: T,
|
||||
_tcx: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<I: Interner, T: IntoIterator> EarlyBinder<I, T> {
|
||||
pub fn transpose_iter(self) -> EarlyBinderIter<I, T::IntoIter> {
|
||||
EarlyBinderIter { t: self.value.into_iter(), _tcx: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, T: Iterator> Iterator for EarlyBinderIter<I, T> {
|
||||
type Item = EarlyBinder<I, T::Item>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.t.next().map(|value| EarlyBinder { value, _tcx: PhantomData })
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.t.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, T: TypeFoldable<I>> ty::EarlyBinder<I, T> {
|
||||
pub fn instantiate(self, tcx: I, args: &[I::GenericArg]) -> T {
|
||||
let mut folder = ArgFolder { tcx, args, binders_passed: 0 };
|
||||
self.value.fold_with(&mut folder)
|
||||
}
|
||||
|
||||
/// Makes the identity replacement `T0 => T0, ..., TN => TN`.
|
||||
/// Conceptually, this converts universally bound variables into placeholders
|
||||
/// when inside of a given item.
|
||||
///
|
||||
/// For example, consider `for<T> fn foo<T>(){ .. }`:
|
||||
/// - Outside of `foo`, `T` is bound (represented by the presence of `EarlyBinder`).
|
||||
/// - Inside of the body of `foo`, we treat `T` as a placeholder by calling
|
||||
/// `instantiate_identity` to discharge the `EarlyBinder`.
|
||||
pub fn instantiate_identity(self) -> T {
|
||||
self.value
|
||||
}
|
||||
|
||||
/// Returns the inner value, but only if it contains no bound vars.
|
||||
pub fn no_bound_vars(self) -> Option<T> {
|
||||
if !self.value.has_param() { Some(self.value) } else { None }
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// The actual instantiation engine itself is a type folder.
|
||||
|
||||
struct ArgFolder<'a, I: Interner> {
|
||||
tcx: I,
|
||||
args: &'a [I::GenericArg],
|
||||
|
||||
/// Number of region binders we have passed through while doing the instantiation
|
||||
binders_passed: u32,
|
||||
}
|
||||
|
||||
impl<'a, I: Interner> TypeFolder<I> for ArgFolder<'a, I> {
|
||||
#[inline]
|
||||
fn interner(&self) -> I {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> {
|
||||
self.binders_passed += 1;
|
||||
let t = t.super_fold_with(self);
|
||||
self.binders_passed -= 1;
|
||||
t
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: I::Region) -> I::Region {
|
||||
// Note: This routine only handles regions that are bound on
|
||||
// type declarations and other outer declarations, not those
|
||||
// bound in *fn types*. Region instantiation of the bound
|
||||
// regions that appear in a function signature is done using
|
||||
// the specialized routine `ty::replace_late_regions()`.
|
||||
match r.kind() {
|
||||
ty::ReEarlyParam(data) => {
|
||||
let rk = self.args.get(data.index() as usize).map(|k| k.kind());
|
||||
match rk {
|
||||
Some(ty::GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt),
|
||||
Some(other) => self.region_param_expected(data, r, other),
|
||||
None => self.region_param_out_of_range(data, r),
|
||||
}
|
||||
}
|
||||
ty::ReBound(..)
|
||||
| ty::ReLateParam(_)
|
||||
| ty::ReStatic
|
||||
| ty::RePlaceholder(_)
|
||||
| ty::ReErased
|
||||
| ty::ReError(_) => r,
|
||||
ty::ReVar(_) => panic!("unexpected region: {r:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
|
||||
if !t.has_param() {
|
||||
return t;
|
||||
}
|
||||
|
||||
match t.kind() {
|
||||
ty::Param(p) => self.ty_for_param(p, t),
|
||||
_ => t.super_fold_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, c: I::Const) -> I::Const {
|
||||
if let ty::ConstKind::Param(p) = c.kind() {
|
||||
self.const_for_param(p, c)
|
||||
} else {
|
||||
c.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, I: Interner> ArgFolder<'a, I> {
|
||||
fn ty_for_param(&self, p: I::ParamTy, source_ty: I::Ty) -> I::Ty {
|
||||
// Look up the type in the args. It really should be in there.
|
||||
let opt_ty = self.args.get(p.index() as usize).map(|k| k.kind());
|
||||
let ty = match opt_ty {
|
||||
Some(ty::GenericArgKind::Type(ty)) => ty,
|
||||
Some(kind) => self.type_param_expected(p, source_ty, kind),
|
||||
None => self.type_param_out_of_range(p, source_ty),
|
||||
};
|
||||
|
||||
self.shift_vars_through_binders(ty)
|
||||
}
|
||||
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn type_param_expected(&self, p: I::ParamTy, ty: I::Ty, kind: ty::GenericArgKind<I>) -> ! {
|
||||
panic!(
|
||||
"expected type for `{:?}` ({:?}/{}) but found {:?} when instantiating, args={:?}",
|
||||
p,
|
||||
ty,
|
||||
p.index(),
|
||||
kind,
|
||||
self.args,
|
||||
)
|
||||
}
|
||||
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn type_param_out_of_range(&self, p: I::ParamTy, ty: I::Ty) -> ! {
|
||||
panic!(
|
||||
"type parameter `{:?}` ({:?}/{}) out of range when instantiating, args={:?}",
|
||||
p,
|
||||
ty,
|
||||
p.index(),
|
||||
self.args,
|
||||
)
|
||||
}
|
||||
|
||||
fn const_for_param(&self, p: I::ParamConst, source_ct: I::Const) -> I::Const {
|
||||
// Look up the const in the args. It really should be in there.
|
||||
let opt_ct = self.args.get(p.index() as usize).map(|k| k.kind());
|
||||
let ct = match opt_ct {
|
||||
Some(ty::GenericArgKind::Const(ct)) => ct,
|
||||
Some(kind) => self.const_param_expected(p, source_ct, kind),
|
||||
None => self.const_param_out_of_range(p, source_ct),
|
||||
};
|
||||
|
||||
self.shift_vars_through_binders(ct)
|
||||
}
|
||||
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn const_param_expected(
|
||||
&self,
|
||||
p: I::ParamConst,
|
||||
ct: I::Const,
|
||||
kind: ty::GenericArgKind<I>,
|
||||
) -> ! {
|
||||
panic!(
|
||||
"expected const for `{:?}` ({:?}/{}) but found {:?} when instantiating args={:?}",
|
||||
p,
|
||||
ct,
|
||||
p.index(),
|
||||
kind,
|
||||
self.args,
|
||||
)
|
||||
}
|
||||
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn const_param_out_of_range(&self, p: I::ParamConst, ct: I::Const) -> ! {
|
||||
panic!(
|
||||
"const parameter `{:?}` ({:?}/{}) out of range when instantiating args={:?}",
|
||||
p,
|
||||
ct,
|
||||
p.index(),
|
||||
self.args,
|
||||
)
|
||||
}
|
||||
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn region_param_expected(
|
||||
&self,
|
||||
ebr: I::EarlyParamRegion,
|
||||
r: I::Region,
|
||||
kind: ty::GenericArgKind<I>,
|
||||
) -> ! {
|
||||
panic!(
|
||||
"expected region for `{:?}` ({:?}/{}) but found {:?} when instantiating args={:?}",
|
||||
ebr,
|
||||
r,
|
||||
ebr.index(),
|
||||
kind,
|
||||
self.args,
|
||||
)
|
||||
}
|
||||
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn region_param_out_of_range(&self, ebr: I::EarlyParamRegion, r: I::Region) -> ! {
|
||||
panic!(
|
||||
"const parameter `{:?}` ({:?}/{}) out of range when instantiating args={:?}",
|
||||
ebr,
|
||||
r,
|
||||
ebr.index(),
|
||||
self.args,
|
||||
)
|
||||
}
|
||||
|
||||
/// It is sometimes necessary to adjust the De Bruijn indices during instantiation. This occurs
|
||||
/// when we are instantating a type with escaping bound vars into a context where we have
|
||||
/// passed through binders. That's quite a mouthful. Let's see an example:
|
||||
///
|
||||
/// ```
|
||||
/// type Func<A> = fn(A);
|
||||
/// type MetaFunc = for<'a> fn(Func<&'a i32>);
|
||||
/// ```
|
||||
///
|
||||
/// The type `MetaFunc`, when fully expanded, will be
|
||||
/// ```ignore (illustrative)
|
||||
/// for<'a> fn(fn(&'a i32))
|
||||
/// // ^~ ^~ ^~~
|
||||
/// // | | |
|
||||
/// // | | DebruijnIndex of 2
|
||||
/// // Binders
|
||||
/// ```
|
||||
/// Here the `'a` lifetime is bound in the outer function, but appears as an argument of the
|
||||
/// inner one. Therefore, that appearance will have a DebruijnIndex of 2, because we must skip
|
||||
/// over the inner binder (remember that we count De Bruijn indices from 1). However, in the
|
||||
/// definition of `MetaFunc`, the binder is not visible, so the type `&'a i32` will have a
|
||||
/// De Bruijn index of 1. It's only during the instantiation that we can see we must increase the
|
||||
/// depth by 1 to account for the binder that we passed through.
|
||||
///
|
||||
/// As a second example, consider this twist:
|
||||
///
|
||||
/// ```
|
||||
/// type FuncTuple<A> = (A,fn(A));
|
||||
/// type MetaFuncTuple = for<'a> fn(FuncTuple<&'a i32>);
|
||||
/// ```
|
||||
///
|
||||
/// Here the final type will be:
|
||||
/// ```ignore (illustrative)
|
||||
/// for<'a> fn((&'a i32, fn(&'a i32)))
|
||||
/// // ^~~ ^~~
|
||||
/// // | |
|
||||
/// // DebruijnIndex of 1 |
|
||||
/// // DebruijnIndex of 2
|
||||
/// ```
|
||||
/// As indicated in the diagram, here the same type `&'a i32` is instantiated once, but in the
|
||||
/// first case we do not increase the De Bruijn index and in the second case we do. The reason
|
||||
/// is that only in the second case have we passed through a fn binder.
|
||||
fn shift_vars_through_binders<T: TypeFoldable<I>>(&self, val: T) -> T {
|
||||
debug!(
|
||||
"shift_vars(val={:?}, binders_passed={:?}, has_escaping_bound_vars={:?})",
|
||||
val,
|
||||
self.binders_passed,
|
||||
val.has_escaping_bound_vars()
|
||||
);
|
||||
|
||||
if self.binders_passed == 0 || !val.has_escaping_bound_vars() {
|
||||
return val;
|
||||
}
|
||||
|
||||
let result = ty::fold::shift_vars(TypeFolder::interner(self), val, self.binders_passed);
|
||||
debug!("shift_vars: shifted result = {:?}", result);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn shift_region_through_binders(&self, region: I::Region) -> I::Region {
|
||||
if self.binders_passed == 0 || !region.has_escaping_bound_vars() {
|
||||
return region;
|
||||
}
|
||||
ty::fold::shift_region(self.tcx, region, self.binders_passed)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,8 +47,10 @@
|
|||
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
use std::mem;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::visit::TypeVisitable;
|
||||
use crate::inherent::*;
|
||||
use crate::visit::{TypeVisitable, TypeVisitableExt as _};
|
||||
use crate::{self as ty, Interner, Lrc};
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
|
|
@ -325,3 +327,95 @@ impl<I: Interner, T: TypeFoldable<I>, Ix: Idx> TypeFoldable<I> for IndexVec<Ix,
|
|||
self.raw.try_fold_with(folder).map(IndexVec::from_raw)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Shifter
|
||||
//
|
||||
// Shifts the De Bruijn indices on all escaping bound vars by a
|
||||
// fixed amount. Useful in instantiation or when otherwise introducing
|
||||
// a binding level that is not intended to capture the existing bound
|
||||
// vars. See comment on `shift_vars_through_binders` method in
|
||||
// `rustc_middle/src/ty/generic_args.rs` for more details.
|
||||
|
||||
struct Shifter<I: Interner> {
|
||||
tcx: I,
|
||||
current_index: ty::DebruijnIndex,
|
||||
amount: u32,
|
||||
}
|
||||
|
||||
impl<I: Interner> Shifter<I> {
|
||||
pub fn new(tcx: I, amount: u32) -> Self {
|
||||
Shifter { tcx, current_index: ty::INNERMOST, amount }
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> TypeFolder<I> for Shifter<I> {
|
||||
fn interner(&self) -> I {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> {
|
||||
self.current_index.shift_in(1);
|
||||
let t = t.super_fold_with(self);
|
||||
self.current_index.shift_out(1);
|
||||
t
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: I::Region) -> I::Region {
|
||||
match r.kind() {
|
||||
ty::ReBound(debruijn, br) if debruijn >= self.current_index => {
|
||||
let debruijn = debruijn.shifted_in(self.amount);
|
||||
Region::new_bound(self.tcx, debruijn, br)
|
||||
}
|
||||
_ => r,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
|
||||
match ty.kind() {
|
||||
ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => {
|
||||
let debruijn = debruijn.shifted_in(self.amount);
|
||||
Ty::new_bound(self.tcx, debruijn, bound_ty)
|
||||
}
|
||||
|
||||
_ if ty.has_vars_bound_at_or_above(self.current_index) => ty.super_fold_with(self),
|
||||
_ => ty,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, ct: I::Const) -> I::Const {
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Bound(debruijn, bound_ct) if debruijn >= self.current_index => {
|
||||
let debruijn = debruijn.shifted_in(self.amount);
|
||||
Const::new_bound(self.tcx, debruijn, bound_ct, ct.ty())
|
||||
}
|
||||
_ => ct.super_fold_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
|
||||
if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shift_region<I: Interner>(tcx: I, region: I::Region, amount: u32) -> I::Region {
|
||||
match region.kind() {
|
||||
ty::ReBound(debruijn, br) if amount > 0 => {
|
||||
Region::new_bound(tcx, debruijn.shifted_in(amount), br)
|
||||
}
|
||||
_ => region,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shift_vars<I: Interner, T>(tcx: I, value: T, amount: u32) -> T
|
||||
where
|
||||
T: TypeFoldable<I>,
|
||||
{
|
||||
debug!("shift_vars(value={:?}, amount={})", value, amount);
|
||||
|
||||
if amount == 0 || !value.has_escaping_bound_vars() {
|
||||
return value;
|
||||
}
|
||||
|
||||
value.fold_with(&mut Shifter::new(tcx, amount))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ pub trait Ty<I: Interner<Ty = Self>>:
|
|||
|
||||
fn new_var(interner: I, var: ty::TyVid) -> Self;
|
||||
|
||||
fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundTy) -> Self;
|
||||
|
||||
fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self;
|
||||
|
||||
fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy<I>) -> Self;
|
||||
|
|
@ -65,7 +67,10 @@ pub trait Region<I: Interner<Region = Self>>:
|
|||
+ Into<I::GenericArg>
|
||||
+ IntoKind<Kind = ty::RegionKind<I>>
|
||||
+ Flags
|
||||
+ TypeVisitable<I>
|
||||
{
|
||||
fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundRegion) -> Self;
|
||||
|
||||
fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self;
|
||||
|
||||
fn new_static(interner: I) -> Self;
|
||||
|
|
@ -87,6 +92,8 @@ pub trait Const<I: Interner<Const = Self>>:
|
|||
|
||||
fn new_var(interner: I, var: ty::ConstVid, ty: I::Ty) -> Self;
|
||||
|
||||
fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundConst, ty: I::Ty) -> Self;
|
||||
|
||||
fn new_anon_bound(
|
||||
interner: I,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
|
|
@ -162,3 +169,7 @@ pub trait BoundVarLike<I: Interner> {
|
|||
|
||||
fn assert_eq(self, var: I::BoundVarKind);
|
||||
}
|
||||
|
||||
pub trait ParamLike {
|
||||
fn index(self) -> u32;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,26 +7,22 @@ use crate::inherent::*;
|
|||
use crate::ir_print::IrPrint;
|
||||
use crate::solve::inspect::CanonicalGoalEvaluationStep;
|
||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
||||
use crate::{
|
||||
AliasTerm, AliasTermKind, AliasTy, AliasTyKind, CanonicalVarInfo, CoercePredicate,
|
||||
DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, FnSig, GenericArgKind,
|
||||
NormalizesTo, ProjectionPredicate, SubtypePredicate, TermKind, TraitPredicate, TraitRef,
|
||||
};
|
||||
use crate::{self as ty, DebugWithInfcx};
|
||||
|
||||
pub trait Interner:
|
||||
Sized
|
||||
+ Copy
|
||||
+ IrPrint<AliasTy<Self>>
|
||||
+ IrPrint<AliasTerm<Self>>
|
||||
+ IrPrint<TraitRef<Self>>
|
||||
+ IrPrint<TraitPredicate<Self>>
|
||||
+ IrPrint<ExistentialTraitRef<Self>>
|
||||
+ IrPrint<ExistentialProjection<Self>>
|
||||
+ IrPrint<ProjectionPredicate<Self>>
|
||||
+ IrPrint<NormalizesTo<Self>>
|
||||
+ IrPrint<SubtypePredicate<Self>>
|
||||
+ IrPrint<CoercePredicate<Self>>
|
||||
+ IrPrint<FnSig<Self>>
|
||||
+ IrPrint<ty::AliasTy<Self>>
|
||||
+ IrPrint<ty::AliasTerm<Self>>
|
||||
+ IrPrint<ty::TraitRef<Self>>
|
||||
+ IrPrint<ty::TraitPredicate<Self>>
|
||||
+ IrPrint<ty::ExistentialTraitRef<Self>>
|
||||
+ IrPrint<ty::ExistentialProjection<Self>>
|
||||
+ IrPrint<ty::ProjectionPredicate<Self>>
|
||||
+ IrPrint<ty::NormalizesTo<Self>>
|
||||
+ IrPrint<ty::SubtypePredicate<Self>>
|
||||
+ IrPrint<ty::CoercePredicate<Self>>
|
||||
+ IrPrint<ty::FnSig<Self>>
|
||||
{
|
||||
type DefId: Copy + Debug + Hash + Eq + TypeVisitable<Self>;
|
||||
type AdtDef: Copy + Debug + Hash + Eq;
|
||||
|
|
@ -39,9 +35,9 @@ pub trait Interner:
|
|||
+ DebugWithInfcx<Self>
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ IntoKind<Kind = GenericArgKind<Self>>
|
||||
+ IntoKind<Kind = ty::GenericArgKind<Self>>
|
||||
+ TypeVisitable<Self>;
|
||||
type Term: Copy + Debug + Hash + Eq + IntoKind<Kind = TermKind<Self>> + TypeVisitable<Self>;
|
||||
type Term: Copy + Debug + Hash + Eq + IntoKind<Kind = ty::TermKind<Self>> + TypeVisitable<Self>;
|
||||
|
||||
type BoundVarKinds: Copy
|
||||
+ Debug
|
||||
|
|
@ -51,7 +47,7 @@ pub trait Interner:
|
|||
+ Default;
|
||||
type BoundVarKind: Copy + Debug + Hash + Eq;
|
||||
|
||||
type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator<Item = CanonicalVarInfo<Self>>;
|
||||
type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator<Item = ty::CanonicalVarInfo<Self>>;
|
||||
type PredefinedOpaques: Copy + Debug + Hash + Eq;
|
||||
type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable<Self>;
|
||||
type ExternalConstraints: Copy + Debug + Hash + Eq;
|
||||
|
|
@ -65,7 +61,7 @@ pub trait Interner:
|
|||
type Ty: Ty<Self>;
|
||||
type Tys: Tys<Self>;
|
||||
type FnInputTys: Copy + Debug + Hash + Eq + Deref<Target = [Self::Ty]> + TypeVisitable<Self>;
|
||||
type ParamTy: Copy + Debug + Hash + Eq;
|
||||
type ParamTy: Copy + Debug + Hash + Eq + ParamLike;
|
||||
type BoundTy: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
|
||||
type PlaceholderTy: PlaceholderLike;
|
||||
|
||||
|
|
@ -81,14 +77,14 @@ pub trait Interner:
|
|||
// Kinds of consts
|
||||
type Const: Const<Self>;
|
||||
type PlaceholderConst: PlaceholderLike;
|
||||
type ParamConst: Copy + Debug + Hash + Eq;
|
||||
type ParamConst: Copy + Debug + Hash + Eq + ParamLike;
|
||||
type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
|
||||
type ValueConst: Copy + Debug + Hash + Eq;
|
||||
type ExprConst: Copy + DebugWithInfcx<Self> + Hash + Eq;
|
||||
|
||||
// Kinds of regions
|
||||
type Region: Region<Self>;
|
||||
type EarlyParamRegion: Copy + Debug + Hash + Eq;
|
||||
type EarlyParamRegion: Copy + Debug + Hash + Eq + ParamLike;
|
||||
type LateParamRegion: Copy + Debug + Hash + Eq;
|
||||
type BoundRegion: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
|
||||
type PlaceholderRegion: PlaceholderLike;
|
||||
|
|
@ -99,23 +95,23 @@ pub trait Interner:
|
|||
type Clause: Clause<Self>;
|
||||
type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags;
|
||||
|
||||
fn mk_canonical_var_infos(self, infos: &[CanonicalVarInfo<Self>]) -> Self::CanonicalVars;
|
||||
fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars;
|
||||
|
||||
type GenericsOf: GenericsOf<Self>;
|
||||
fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf;
|
||||
|
||||
// FIXME: Remove after uplifting `EarlyBinder`
|
||||
fn type_of_instantiated(self, def_id: Self::DefId, args: Self::GenericArgs) -> Self::Ty;
|
||||
fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder<Self, Self::Ty>;
|
||||
|
||||
fn alias_ty_kind(self, alias: AliasTy<Self>) -> AliasTyKind;
|
||||
fn alias_ty_kind(self, alias: ty::AliasTy<Self>) -> ty::AliasTyKind;
|
||||
|
||||
fn alias_term_kind(self, alias: AliasTerm<Self>) -> AliasTermKind;
|
||||
fn alias_term_kind(self, alias: ty::AliasTerm<Self>) -> ty::AliasTermKind;
|
||||
|
||||
fn trait_ref_and_own_args_for_alias(
|
||||
self,
|
||||
def_id: Self::DefId,
|
||||
args: Self::GenericArgs,
|
||||
) -> (TraitRef<Self>, Self::OwnItemArgs);
|
||||
) -> (ty::TraitRef<Self>, Self::OwnItemArgs);
|
||||
|
||||
fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#![cfg_attr(
|
||||
feature = "nightly",
|
||||
feature(associated_type_defaults, min_specialization, never_type, rustc_attrs)
|
||||
feature(associated_type_defaults, min_specialization, never_type, rustc_attrs, negative_impls)
|
||||
)]
|
||||
#![allow(rustc::usage_of_ty_tykind)]
|
||||
#![cfg_attr(feature = "nightly", allow(internal_features))]
|
||||
|
|
|
|||
|
|
@ -567,7 +567,7 @@ impl<I: Interner> AliasTerm<I> {
|
|||
I::Const::new_unevaluated(
|
||||
interner,
|
||||
ty::UnevaluatedConst::new(self.def_id, self.args),
|
||||
interner.type_of_instantiated(self.def_id, self.args),
|
||||
interner.type_of(self.def_id).instantiate(interner, &self.args),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -904,9 +904,6 @@
|
|||
# on linux
|
||||
#src-tarball = true
|
||||
|
||||
# Whether to allow failures when building tools
|
||||
#missing-tools = false
|
||||
|
||||
# List of compression formats to use when generating dist tarballs. The list of
|
||||
# formats is provided to rust-installer, which must support all of them.
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit e15130618237eb3e2d4b622549f9647b4c1d9ca3
|
||||
Subproject commit 5e05efa87905fb5b351a2bc5644d60c57d6d9327
|
||||
|
|
@ -137,10 +137,13 @@
|
|||
//!
|
||||
//! [^extern_fn]: this remains true for any argument/return types and any other ABI: `extern "abi" fn` (_e.g._, `extern "system" fn`)
|
||||
//!
|
||||
//! Under some conditions the above types `T` are also null pointer optimized when wrapped in a [`Result`][result_repr].
|
||||
//!
|
||||
//! [`Box<U>`]: ../../std/boxed/struct.Box.html
|
||||
//! [`num::NonZero*`]: crate::num
|
||||
//! [`ptr::NonNull<U>`]: crate::ptr::NonNull
|
||||
//! [function call ABI]: ../primitive.fn.html#abi-compatibility
|
||||
//! [result_repr]: crate::result#representation
|
||||
//!
|
||||
//! This is called the "null pointer optimization" or NPO.
|
||||
//!
|
||||
|
|
|
|||
|
|
@ -228,6 +228,27 @@
|
|||
//! [`Err(E)`]: Err
|
||||
//! [io::Error]: ../../std/io/struct.Error.html "io::Error"
|
||||
//!
|
||||
//! # Representation
|
||||
//!
|
||||
//! In some cases, [`Result<T, E>`] will gain the same size, alignment, and ABI
|
||||
//! guarantees as [`Option<U>`] has. One of either the `T` or `E` type must be a
|
||||
//! type that qualifies for the `Option` [representation guarantees][opt-rep],
|
||||
//! and the *other* type must meet all of the following conditions:
|
||||
//! * Is a zero-sized type with alignment 1 (a "1-ZST").
|
||||
//! * Has no fields.
|
||||
//! * Does not have the `#[non_exhaustive]` attribute.
|
||||
//!
|
||||
//! For example, `NonZeroI32` qualifies for the `Option` representation
|
||||
//! guarantees, and `()` is a zero-sized type with alignment 1, no fields, and
|
||||
//! it isn't `non_exhaustive`. This means that both `Result<NonZeroI32, ()>` and
|
||||
//! `Result<(), NonZeroI32>` have the same size, alignment, and ABI guarantees
|
||||
//! as `Option<NonZeroI32>`. The only difference is the implied semantics:
|
||||
//! * `Option<NonZeroI32>` is "a non-zero i32 might be present"
|
||||
//! * `Result<NonZeroI32, ()>` is "a non-zero i32 success result, if any"
|
||||
//! * `Result<(), NonZeroI32>` is "a non-zero i32 error result, if any"
|
||||
//!
|
||||
//! [opt-rep]: ../option/index.html#representation "Option Representation"
|
||||
//!
|
||||
//! # Method overview
|
||||
//!
|
||||
//! In addition to working with pattern matching, [`Result`] provides a
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ const UNROLL_INNER: usize = 4;
|
|||
|
||||
#[inline]
|
||||
pub(super) fn count_chars(s: &str) -> usize {
|
||||
if s.len() < USIZE_SIZE * UNROLL_INNER {
|
||||
if cfg!(feature = "optimize_for_size") || s.len() < USIZE_SIZE * UNROLL_INNER {
|
||||
// Avoid entering the optimized implementation for strings where the
|
||||
// difference is not likely to matter, or where it might even be slower.
|
||||
// That said, a ton of thought was not spent on the particular threshold
|
||||
|
|
|
|||
|
|
@ -24,11 +24,11 @@ hashbrown = { version = "0.14", default-features = false, features = ['rustc-dep
|
|||
std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = ['rustc-dep-of-std'] }
|
||||
|
||||
# Dependencies of the `backtrace` crate
|
||||
rustc-demangle = { version = "0.1.21", features = ['rustc-dep-of-std'] }
|
||||
rustc-demangle = { version = "0.1.24", features = ['rustc-dep-of-std'] }
|
||||
|
||||
[target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies]
|
||||
miniz_oxide = { version = "0.7.0", optional = true, default-features = false }
|
||||
addr2line = { version = "0.21.0", optional = true, default-features = false }
|
||||
addr2line = { version = "0.22.0", optional = true, default-features = false }
|
||||
|
||||
[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
|
||||
libc = { version = "0.2.153", default-features = false, features = ['rustc-dep-of-std'], public = true }
|
||||
|
|
|
|||
|
|
@ -314,7 +314,6 @@ pub struct Config {
|
|||
pub save_toolstates: Option<PathBuf>,
|
||||
pub print_step_timings: bool,
|
||||
pub print_step_rusage: bool,
|
||||
pub missing_tools: bool, // FIXME: Deprecated field. Remove it at 2024.
|
||||
|
||||
// Fallback musl-root for all targets
|
||||
pub musl_root: Option<PathBuf>,
|
||||
|
|
@ -905,7 +904,6 @@ define_config! {
|
|||
sign_folder: Option<String> = "sign-folder",
|
||||
upload_addr: Option<String> = "upload-addr",
|
||||
src_tarball: Option<bool> = "src-tarball",
|
||||
missing_tools: Option<bool> = "missing-tools",
|
||||
compression_formats: Option<Vec<String>> = "compression-formats",
|
||||
compression_profile: Option<String> = "compression-profile",
|
||||
include_mingw_linker: Option<bool> = "include-mingw-linker",
|
||||
|
|
@ -1936,7 +1934,6 @@ impl Config {
|
|||
sign_folder,
|
||||
upload_addr,
|
||||
src_tarball,
|
||||
missing_tools,
|
||||
compression_formats,
|
||||
compression_profile,
|
||||
include_mingw_linker,
|
||||
|
|
@ -1946,7 +1943,6 @@ impl Config {
|
|||
config.dist_compression_formats = compression_formats;
|
||||
set(&mut config.dist_compression_profile, compression_profile);
|
||||
set(&mut config.rust_dist_src, src_tarball);
|
||||
set(&mut config.missing_tools, missing_tools);
|
||||
set(&mut config.dist_include_mingw_linker, include_mingw_linker)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -190,4 +190,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
|
|||
severity: ChangeSeverity::Warning,
|
||||
summary: "`rust.lld` has a new default value of `true` on `x86_64-unknown-linux-gnu`. Starting at stage1, `rust-lld` will thus be this target's default linker. No config changes should be necessary.",
|
||||
},
|
||||
ChangeInfo {
|
||||
change_id: 125535,
|
||||
severity: ChangeSeverity::Warning,
|
||||
summary: "Removed `dist.missing-tools` configuration as it was deprecated long time ago.",
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -270,7 +270,6 @@ else
|
|||
args="$args --volume $root_dir:/checkout$SRC_MOUNT_OPTION"
|
||||
args="$args --volume $objdir:/checkout/obj"
|
||||
args="$args --volume $HOME/.cargo:/cargo"
|
||||
args="$args --volume $HOME/rustsrc:$HOME/rustsrc"
|
||||
args="$args --volume /tmp/toolstate:/tmp/toolstate"
|
||||
|
||||
id=$(id -u)
|
||||
|
|
|
|||
|
|
@ -61,6 +61,12 @@ envs:
|
|||
|
||||
try:
|
||||
<<: *production
|
||||
# The following env var activates faster `try` builds in `opt-dist` by, e.g.
|
||||
# - building only the more commonly useful components (we rarely need e.g. rust-docs in try
|
||||
# builds)
|
||||
# - not running `opt-dist`'s post-optimization smoke tests on the resulting toolchain
|
||||
#
|
||||
# If you *want* these to happen however, temporarily uncomment it before triggering a try build.
|
||||
DIST_TRY_BUILD: 1
|
||||
|
||||
auto:
|
||||
|
|
|
|||
|
|
@ -4,21 +4,21 @@
|
|||
# We check both in rust-lang/rust and in a submodule to make sure both are
|
||||
# accurate. Submodules are checked out significantly later than the main
|
||||
# repository in this script, so settings can (and do!) change between then.
|
||||
#
|
||||
# Linux (and maybe macOS) builders don't currently have dos2unix so just only
|
||||
# run this step on Windows.
|
||||
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
|
||||
source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
|
||||
|
||||
if isWindows; then
|
||||
# print out the git configuration so we can better investigate failures in
|
||||
# the following
|
||||
git config --list --show-origin
|
||||
dos2unix -ih Cargo.lock src/tools/rust-installer/install-template.sh
|
||||
endings=$(dos2unix -ic Cargo.lock src/tools/rust-installer/install-template.sh)
|
||||
# if endings has non-zero length, error out
|
||||
if [ -n "$endings" ]; then exit 1 ; fi
|
||||
# print out the git configuration so we can better investigate failures in
|
||||
# the following
|
||||
git config --list --show-origin
|
||||
# -U is necessary on Windows to stop grep automatically converting the line ending
|
||||
endings=$(grep -Ul $(printf '\r$') Cargo.lock src/tools/cargo/Cargo.lock) || true
|
||||
# if endings has non-zero length, error out
|
||||
if [[ -n $endings ]]; then
|
||||
echo "Error: found DOS line endings"
|
||||
# Print the files with DOS line endings
|
||||
echo "$endings"
|
||||
exit 1
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -627,7 +627,7 @@ impl Item {
|
|||
) -> hir::FnHeader {
|
||||
let sig = tcx.fn_sig(def_id).skip_binder();
|
||||
let constness =
|
||||
if tcx.is_const_fn(def_id) && is_unstable_const_fn(tcx, def_id).is_none() {
|
||||
if tcx.is_const_fn(def_id) || is_unstable_const_fn(tcx, def_id).is_some() {
|
||||
hir::Constness::Const
|
||||
} else {
|
||||
hir::Constness::NotConst
|
||||
|
|
@ -649,9 +649,8 @@ impl Item {
|
|||
hir::Safety::Unsafe
|
||||
},
|
||||
abi,
|
||||
constness: if abi == Abi::RustIntrinsic
|
||||
&& tcx.is_const_fn(def_id)
|
||||
&& is_unstable_const_fn(tcx, def_id).is_none()
|
||||
constness: if tcx.is_const_fn(def_id)
|
||||
|| is_unstable_const_fn(tcx, def_id).is_some()
|
||||
{
|
||||
hir::Constness::Const
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use std::fmt::{self, Display, Write};
|
|||
use std::iter::{self, once};
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_attr::{ConstStability, StabilityLevel};
|
||||
use rustc_attr::{ConstStability, StabilityLevel, StableSince};
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir as hir;
|
||||
|
|
@ -1633,17 +1633,24 @@ impl PrintWithSpace for hir::Mutability {
|
|||
|
||||
pub(crate) fn print_constness_with_space(
|
||||
c: &hir::Constness,
|
||||
s: Option<ConstStability>,
|
||||
overall_stab: Option<StableSince>,
|
||||
const_stab: Option<ConstStability>,
|
||||
) -> &'static str {
|
||||
match (c, s) {
|
||||
// const stable or when feature(staged_api) is not set
|
||||
(
|
||||
hir::Constness::Const,
|
||||
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }),
|
||||
)
|
||||
| (hir::Constness::Const, None) => "const ",
|
||||
// const unstable or not const
|
||||
_ => "",
|
||||
match c {
|
||||
hir::Constness::Const => match (overall_stab, const_stab) {
|
||||
// const stable...
|
||||
(_, Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }))
|
||||
// ...or when feature(staged_api) is not set...
|
||||
| (_, None)
|
||||
// ...or when const unstable, but overall unstable too
|
||||
| (None, Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. })) => {
|
||||
"const "
|
||||
}
|
||||
// const unstable (and overall stable)
|
||||
(Some(_), Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. })) => "",
|
||||
},
|
||||
// not const
|
||||
hir::Constness::NotConst => "",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -928,9 +928,11 @@ fn assoc_method(
|
|||
// FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
|
||||
// this condition.
|
||||
let constness = match render_mode {
|
||||
RenderMode::Normal => {
|
||||
print_constness_with_space(&header.constness, meth.const_stability(tcx))
|
||||
}
|
||||
RenderMode::Normal => print_constness_with_space(
|
||||
&header.constness,
|
||||
meth.stable_since(tcx),
|
||||
meth.const_stability(tcx),
|
||||
),
|
||||
RenderMode::ForDeref { .. } => "",
|
||||
};
|
||||
let asyncness = header.asyncness.print_with_space();
|
||||
|
|
@ -1016,18 +1018,23 @@ fn render_stability_since_raw_with_extra(
|
|||
.map(|since| (format!("const since {since}"), format!("const: {since}")))
|
||||
}
|
||||
Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }) => {
|
||||
let unstable = if let Some(n) = issue {
|
||||
format!(
|
||||
"<a \
|
||||
if stable_version.is_none() {
|
||||
// don't display const unstable if entirely unstable
|
||||
None
|
||||
} else {
|
||||
let unstable = if let Some(n) = issue {
|
||||
format!(
|
||||
"<a \
|
||||
href=\"https://github.com/rust-lang/rust/issues/{n}\" \
|
||||
title=\"Tracking issue for {feature}\"\
|
||||
>unstable</a>"
|
||||
)
|
||||
} else {
|
||||
String::from("unstable")
|
||||
};
|
||||
)
|
||||
} else {
|
||||
String::from("unstable")
|
||||
};
|
||||
|
||||
Some((String::from("const unstable"), format!("const: {unstable}")))
|
||||
Some((String::from("const unstable"), format!("const: {unstable}")))
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -615,7 +615,18 @@ fn extra_info_tags<'a, 'tcx: 'a>(
|
|||
fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &clean::Function) {
|
||||
let tcx = cx.tcx();
|
||||
let header = it.fn_header(tcx).expect("printing a function which isn't a function");
|
||||
let constness = print_constness_with_space(&header.constness, it.const_stability(tcx));
|
||||
debug!(
|
||||
"item_function/const: {:?} {:?} {:?} {:?}",
|
||||
it.name,
|
||||
&header.constness,
|
||||
it.stable_since(tcx),
|
||||
it.const_stability(tcx),
|
||||
);
|
||||
let constness = print_constness_with_space(
|
||||
&header.constness,
|
||||
it.stable_since(tcx),
|
||||
it.const_stability(tcx),
|
||||
);
|
||||
let safety = header.safety.print_with_space();
|
||||
let abi = print_abi_with_space(header.abi).to_string();
|
||||
let asyncness = header.asyncness.print_with_space();
|
||||
|
|
|
|||
|
|
@ -441,10 +441,19 @@ impl<'a> LintExtractor<'a> {
|
|||
fs::write(&tempfile, source)
|
||||
.map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?;
|
||||
let mut cmd = Command::new(self.rustc_path);
|
||||
if options.contains(&"edition2015") {
|
||||
cmd.arg("--edition=2015");
|
||||
} else {
|
||||
if options.contains(&"edition2024") {
|
||||
cmd.arg("--edition=2024");
|
||||
} else if options.contains(&"edition2021") {
|
||||
cmd.arg("--edition=2021");
|
||||
} else if options.contains(&"edition2018") {
|
||||
cmd.arg("--edition=2018");
|
||||
} else if options.contains(&"edition2015") {
|
||||
cmd.arg("--edition=2015");
|
||||
} else if options.contains(&"edition") {
|
||||
panic!("lint-docs: unknown edition");
|
||||
} else {
|
||||
// defaults to latest edition
|
||||
cmd.arg("--edition=2021");
|
||||
}
|
||||
cmd.arg("--error-format=json");
|
||||
cmd.arg("--target").arg(self.rustc_target);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
thread 'rustc' panicked at compiler/rustc_mir_transform/src/validate.rs:LL:CC:
|
||||
broken MIR in Item(DefId) (after phase change to runtime-optimized) at bb0[1]:
|
||||
(*(_2.0: *mut i32)), has deref at the wrong place
|
||||
place (*(_2.0: *mut i32)) has deref as a later projection (it is only permitted as the first projection)
|
||||
stack backtrace:
|
||||
|
||||
error: the compiler unexpectedly panicked. this is a bug.
|
||||
|
|
|
|||
|
|
@ -51,7 +51,10 @@ impl Diff {
|
|||
/// Specify the actual output for the diff from a file.
|
||||
pub fn actual_file<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
|
||||
let path = path.as_ref();
|
||||
let content = std::fs::read_to_string(path).expect("failed to read file");
|
||||
let content = match std::fs::read_to_string(path) {
|
||||
Ok(c) => c,
|
||||
Err(e) => panic!("failed to read `{}`: {:?}", path.display(), e),
|
||||
};
|
||||
let name = path.to_string_lossy().to_string();
|
||||
|
||||
self.actual = Some(content);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ pub mod rustc;
|
|||
pub mod rustdoc;
|
||||
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, Output};
|
||||
|
||||
|
|
@ -201,6 +203,71 @@ pub fn set_host_rpath(cmd: &mut Command) {
|
|||
});
|
||||
}
|
||||
|
||||
/// Copy a directory into another.
|
||||
pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
|
||||
fn copy_dir_all_inner(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
|
||||
let dst = dst.as_ref();
|
||||
if !dst.is_dir() {
|
||||
fs::create_dir_all(&dst)?;
|
||||
}
|
||||
for entry in fs::read_dir(src)? {
|
||||
let entry = entry?;
|
||||
let ty = entry.file_type()?;
|
||||
if ty.is_dir() {
|
||||
copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?;
|
||||
} else {
|
||||
fs::copy(entry.path(), dst.join(entry.file_name()))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
if let Err(e) = copy_dir_all_inner(&src, &dst) {
|
||||
// Trying to give more context about what exactly caused the failure
|
||||
panic!(
|
||||
"failed to copy `{}` to `{}`: {:?}",
|
||||
src.as_ref().display(),
|
||||
dst.as_ref().display(),
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Check that all files in `dir1` exist and have the same content in `dir2`. Panic otherwise.
|
||||
pub fn recursive_diff(dir1: impl AsRef<Path>, dir2: impl AsRef<Path>) {
|
||||
fn read_file(path: &Path) -> Vec<u8> {
|
||||
match fs::read(path) {
|
||||
Ok(c) => c,
|
||||
Err(e) => panic!("Failed to read `{}`: {:?}", path.display(), e),
|
||||
}
|
||||
}
|
||||
|
||||
let dir2 = dir2.as_ref();
|
||||
for entry in fs::read_dir(dir1).unwrap() {
|
||||
let entry = entry.unwrap();
|
||||
let entry_name = entry.file_name();
|
||||
let path = entry.path();
|
||||
|
||||
if path.is_dir() {
|
||||
recursive_diff(&path, &dir2.join(entry_name));
|
||||
} else {
|
||||
let path2 = dir2.join(entry_name);
|
||||
let file1 = read_file(&path);
|
||||
let file2 = read_file(&path2);
|
||||
|
||||
// We don't use `assert_eq!` because they are `Vec<u8>`, so not great for display.
|
||||
// Why not using String? Because there might be minified files or even potentially
|
||||
// binary ones, so that would display useless output.
|
||||
assert!(
|
||||
file1 == file2,
|
||||
"`{}` and `{}` have different content",
|
||||
path.display(),
|
||||
path2.display(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct
|
||||
/// containing a `cmd: Command` field and a `output` function. The provided helpers are:
|
||||
///
|
||||
|
|
|
|||
|
|
@ -151,6 +151,13 @@ impl Rustdoc {
|
|||
self
|
||||
}
|
||||
|
||||
/// Specify the output format.
|
||||
pub fn output_format(&mut self, format: &str) -> &mut Self {
|
||||
self.cmd.arg("--output-format");
|
||||
self.cmd.arg(format);
|
||||
self
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output {
|
||||
let caller_location = std::panic::Location::caller();
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ run-make/cdylib-fewer-symbols/Makefile
|
|||
run-make/cdylib/Makefile
|
||||
run-make/codegen-options-parsing/Makefile
|
||||
run-make/comment-section/Makefile
|
||||
run-make/compile-stdin/Makefile
|
||||
run-make/compiler-lookup-paths-2/Makefile
|
||||
run-make/compiler-lookup-paths/Makefile
|
||||
run-make/compiler-rt-works-on-mingw/Makefile
|
||||
|
|
@ -227,7 +226,6 @@ run-make/rlib-format-packed-bundled-libs/Makefile
|
|||
run-make/rmeta-preferred/Makefile
|
||||
run-make/rustc-macro-dep-files/Makefile
|
||||
run-make/rustdoc-io-error/Makefile
|
||||
run-make/rustdoc-verify-output-files/Makefile
|
||||
run-make/sanitizer-cdylib-link/Makefile
|
||||
run-make/sanitizer-dylib-link/Makefile
|
||||
run-make/sanitizer-staticlib-link/Makefile
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@ use std::path::{Path, PathBuf};
|
|||
// should all be 1000 or lower. Limits significantly smaller than 1000 are also
|
||||
// desirable, because large numbers of files are unwieldy in general. See issue
|
||||
// #73494.
|
||||
const ENTRY_LIMIT: usize = 900;
|
||||
const ENTRY_LIMIT: u32 = 900;
|
||||
// FIXME: The following limits should be reduced eventually.
|
||||
|
||||
const ISSUES_ENTRY_LIMIT: usize = 1676;
|
||||
const ISSUES_ENTRY_LIMIT: u32 = 1676;
|
||||
|
||||
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
|
||||
"rs", // test source files
|
||||
|
|
@ -53,7 +53,7 @@ const EXTENSION_EXCEPTION_PATHS: &[&str] = &[
|
|||
];
|
||||
|
||||
fn check_entries(tests_path: &Path, bad: &mut bool) {
|
||||
let mut directories: HashMap<PathBuf, usize> = HashMap::new();
|
||||
let mut directories: HashMap<PathBuf, u32> = HashMap::new();
|
||||
|
||||
for dir in Walk::new(&tests_path.join("ui")) {
|
||||
if let Ok(entry) = dir {
|
||||
|
|
@ -62,7 +62,7 @@ fn check_entries(tests_path: &Path, bad: &mut bool) {
|
|||
}
|
||||
}
|
||||
|
||||
let (mut max, mut max_issues) = (0usize, 0usize);
|
||||
let (mut max, mut max_issues) = (0, 0);
|
||||
for (dir_path, count) in directories {
|
||||
let is_issues_dir = tests_path.join("ui/issues") == dir_path;
|
||||
let (limit, maxcnt) = if is_issues_dir {
|
||||
|
|
|
|||
13
tests/crashes/123255.rs
Normal file
13
tests/crashes/123255.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
//@ known-bug: rust-lang/rust#123255
|
||||
//@ edition:2021
|
||||
#![crate_type = "lib"]
|
||||
|
||||
pub fn a() {}
|
||||
|
||||
mod handlers {
|
||||
pub struct C(&());
|
||||
pub fn c() -> impl Fn() -> C {
|
||||
let a1 = ();
|
||||
|| C((crate::a(), a1).into())
|
||||
}
|
||||
}
|
||||
25
tests/crashes/123276.rs
Normal file
25
tests/crashes/123276.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
//@ known-bug: rust-lang/rust#123276
|
||||
//@ edition:2021
|
||||
|
||||
async fn create_task() {
|
||||
_ = Some(async { bind(documentation_filter()) });
|
||||
}
|
||||
|
||||
async fn bind<Fut, F: Filter<Future = Fut>>(_: F) {}
|
||||
|
||||
fn documentation_filter() -> impl Filter {
|
||||
AndThen
|
||||
}
|
||||
|
||||
trait Filter {
|
||||
type Future;
|
||||
}
|
||||
|
||||
struct AndThen;
|
||||
|
||||
impl Filter for AndThen
|
||||
where
|
||||
Foo: Filter,
|
||||
{
|
||||
type Future = ();
|
||||
}
|
||||
15
tests/crashes/123887.rs
Normal file
15
tests/crashes/123887.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
//@ known-bug: rust-lang/rust#123887
|
||||
//@ compile-flags: -Clink-dead-code
|
||||
|
||||
#![feature(extern_types)]
|
||||
#![feature(unsized_fn_params)]
|
||||
|
||||
extern "C" {
|
||||
pub type ExternType;
|
||||
}
|
||||
|
||||
impl ExternType {
|
||||
pub fn f(self) {}
|
||||
}
|
||||
|
||||
pub fn main() {}
|
||||
5
tests/crashes/125013-1.rs
Normal file
5
tests/crashes/125013-1.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
//@ known-bug: rust-lang/rust#125013
|
||||
//@ edition:2021
|
||||
use io::{self as std};
|
||||
use std::ops::Deref::{self as io};
|
||||
pub fn main() {}
|
||||
16
tests/crashes/125013-2.rs
Normal file
16
tests/crashes/125013-2.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
//@ known-bug: rust-lang/rust#125013
|
||||
//@ edition:2021
|
||||
mod a {
|
||||
pub mod b {
|
||||
pub mod c {
|
||||
pub trait D {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use a::*;
|
||||
|
||||
use e as b;
|
||||
use b::c::D as e;
|
||||
|
||||
fn main() { }
|
||||
17
tests/crashes/125014.rs
Normal file
17
tests/crashes/125014.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
//@ known-bug: rust-lang/rust#125014
|
||||
//@ compile-flags: -Znext-solver=coherence
|
||||
#![feature(specialization)]
|
||||
|
||||
trait Foo {}
|
||||
|
||||
impl Foo for <u16 as Assoc>::Output {}
|
||||
|
||||
impl Foo for u32 {}
|
||||
|
||||
trait Assoc {
|
||||
type Output;
|
||||
}
|
||||
impl Output for u32 {}
|
||||
impl Assoc for <u16 as Assoc>::Output {
|
||||
default type Output = bool;
|
||||
}
|
||||
12
tests/crashes/125059.rs
Normal file
12
tests/crashes/125059.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
//@ known-bug: rust-lang/rust#125059
|
||||
#![feature(deref_patterns)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
fn simple_vec(vec: Vec<u32>) -> u32 {
|
||||
(|| match Vec::<u32>::new() {
|
||||
deref!([]) => 100,
|
||||
_ => 2000,
|
||||
})()
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
6
tests/crashes/125323.rs
Normal file
6
tests/crashes/125323.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
//@ known-bug: rust-lang/rust#125323
|
||||
fn main() {
|
||||
for _ in 0..0 {
|
||||
[(); loop {}];
|
||||
}
|
||||
}
|
||||
4
tests/crashes/125476.rs
Normal file
4
tests/crashes/125476.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
//@ known-bug: rust-lang/rust#125476
|
||||
//@ only-x86_64
|
||||
pub struct Data([u8; usize::MAX >> 16]);
|
||||
const _: &'static [Data] = &[];
|
||||
10
tests/crashes/125512.rs
Normal file
10
tests/crashes/125512.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
//@ known-bug: rust-lang/rust#125512
|
||||
//@ edition:2021
|
||||
#![feature(object_safe_for_dispatch)]
|
||||
trait B {
|
||||
fn f(a: A) -> A;
|
||||
}
|
||||
trait A {
|
||||
fn concrete(b: B) -> B;
|
||||
}
|
||||
fn main() {}
|
||||
15
tests/crashes/125553.rs
Normal file
15
tests/crashes/125553.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
//@ known-bug: rust-lang/rust#125553
|
||||
//@ edition:2021
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Foo((u32, u32));
|
||||
|
||||
fn main() {
|
||||
type T = impl Copy(Copy, Clone)
|
||||
let foo: T = Foo((1u32, 1u32));
|
||||
let x = move || {
|
||||
let derive = move || {
|
||||
let Foo((a, b)) = foo;
|
||||
};
|
||||
};
|
||||
}
|
||||
14
tests/crashes/125556.rs
Normal file
14
tests/crashes/125556.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
//@ known-bug: rust-lang/rust#125556
|
||||
//@ compile-flags: -Znext-solver=coherence
|
||||
|
||||
#![feature(generic_const_exprs)]
|
||||
|
||||
pub struct A<const z: [usize; x]> {}
|
||||
|
||||
impl A<2> {
|
||||
pub const fn B() {}
|
||||
}
|
||||
|
||||
impl A<2> {
|
||||
pub const fn B() {}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
# When provided standard input piped directly into rustc, this test checks that the compilation completes successfully and that the output can be executed.
|
||||
# See https://github.com/rust-lang/rust/pull/28805
|
||||
|
||||
# ignore-cross-compile
|
||||
include ../tools.mk
|
||||
|
||||
all:
|
||||
echo 'fn main(){}' | $(RUSTC) -
|
||||
$(call RUN,rust_out)
|
||||
13
tests/run-make/compile-stdin/rmake.rs
Normal file
13
tests/run-make/compile-stdin/rmake.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// When provided standard input piped directly into rustc, this test checks that the compilation
|
||||
// completes successfully and that the output can be executed.
|
||||
//
|
||||
// See <https://github.com/rust-lang/rust/pull/28805>.
|
||||
|
||||
//@ ignore-cross-compile
|
||||
|
||||
use run_make_support::{run, rustc};
|
||||
|
||||
fn main() {
|
||||
rustc().arg("-").stdin("fn main() {}").run();
|
||||
run("rust_out");
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
include ../tools.mk
|
||||
|
||||
OUTPUT_DIR := "$(TMPDIR)/rustdoc"
|
||||
TMP_OUTPUT_DIR := "$(TMPDIR)/tmp-rustdoc"
|
||||
|
||||
all:
|
||||
# Generate html docs
|
||||
$(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR)
|
||||
|
||||
# Copy first output for to check if it's exactly same after second compilation
|
||||
cp -R $(OUTPUT_DIR) $(TMP_OUTPUT_DIR)
|
||||
|
||||
# Generate html docs once again on same output
|
||||
$(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR)
|
||||
|
||||
# Check if everything exactly same
|
||||
$(DIFF) -r $(OUTPUT_DIR) $(TMP_OUTPUT_DIR)
|
||||
|
||||
# Generate json doc on the same output
|
||||
$(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR) -Z unstable-options --output-format json
|
||||
|
||||
# Check if expected json file is generated
|
||||
[ -e $(OUTPUT_DIR)/foobar.json ]
|
||||
|
||||
# Copy first json output to check if it's exactly same after second compilation
|
||||
cp -R $(OUTPUT_DIR)/foobar.json $(TMP_OUTPUT_DIR)/foobar.json
|
||||
|
||||
# Generate json doc on the same output
|
||||
$(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR) -Z unstable-options --output-format json
|
||||
|
||||
# Check if all docs(including both json and html formats) are still the same after multiple compilations
|
||||
$(DIFF) -r $(OUTPUT_DIR) $(TMP_OUTPUT_DIR)
|
||||
49
tests/run-make/rustdoc-verify-output-files/rmake.rs
Normal file
49
tests/run-make/rustdoc-verify-output-files/rmake.rs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
use std::fs::copy;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use run_make_support::{copy_dir_all, recursive_diff, rustdoc, tmp_dir};
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum JsonOutput {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
fn generate_docs(out_dir: &Path, json_output: JsonOutput) {
|
||||
let mut rustdoc = rustdoc();
|
||||
rustdoc.input("src/lib.rs").crate_name("foobar").crate_type("lib").out_dir(&out_dir);
|
||||
if json_output == JsonOutput::Yes {
|
||||
rustdoc.arg("-Zunstable-options").output_format("json");
|
||||
}
|
||||
rustdoc.run();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let out_dir = tmp_dir().join("rustdoc");
|
||||
let tmp_out_dir = tmp_dir().join("tmp-rustdoc");
|
||||
|
||||
// Generate HTML docs.
|
||||
generate_docs(&out_dir, JsonOutput::No);
|
||||
|
||||
// Copy first output for to check if it's exactly same after second compilation.
|
||||
copy_dir_all(&out_dir, &tmp_out_dir);
|
||||
|
||||
// Generate html docs once again on same output.
|
||||
generate_docs(&out_dir, JsonOutput::No);
|
||||
|
||||
// Generate json doc on the same output.
|
||||
generate_docs(&out_dir, JsonOutput::Yes);
|
||||
|
||||
// Check if expected json file is generated.
|
||||
assert!(out_dir.join("foobar.json").is_file());
|
||||
|
||||
// Copy first json output to check if it's exactly same after second compilation.
|
||||
copy(out_dir.join("foobar.json"), tmp_out_dir.join("foobar.json")).unwrap();
|
||||
|
||||
// Generate json doc on the same output.
|
||||
generate_docs(&out_dir, JsonOutput::Yes);
|
||||
|
||||
// Check if all docs(including both json and html formats) are still the same after multiple
|
||||
// compilations.
|
||||
recursive_diff(&out_dir, &tmp_out_dir);
|
||||
}
|
||||
|
|
@ -24,6 +24,12 @@ pub const unsafe fn foo_unsafe() -> u32 { 42 }
|
|||
#[unstable(feature = "humans", issue = "none")]
|
||||
pub const fn foo2() -> u32 { 42 }
|
||||
|
||||
// @has 'foo/fn.foo3.html' '//pre' 'pub const fn foo3() -> u32'
|
||||
// @!hasraw - '//span[@class="since"]'
|
||||
#[unstable(feature = "humans", issue = "none")]
|
||||
#[rustc_const_unstable(feature = "humans", issue = "none")]
|
||||
pub const fn foo3() -> u32 { 42 }
|
||||
|
||||
// @has 'foo/fn.bar2.html' '//pre' 'pub const fn bar2() -> u32'
|
||||
// @has - //span '1.0.0 (const: 1.0.0)'
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
// issue: rust-lang/rust#125520
|
||||
#![feature(generic_const_exprs)]
|
||||
//~^ WARN the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
|
||||
struct Outer<const A: i64, const B: i64>();
|
||||
impl<const A: usize, const B: usize> Outer<A, B>
|
||||
//~^ ERROR the constant `A` is not of type `i64`
|
||||
//~| ERROR the constant `B` is not of type `i64`
|
||||
//~| ERROR mismatched types
|
||||
//~| ERROR mismatched types
|
||||
where
|
||||
[(); A + (B * 2)]:,
|
||||
{
|
||||
fn i() -> Self {
|
||||
//~^ ERROR the constant `A` is not of type `i64`
|
||||
//~| ERROR the constant `B` is not of type `i64`
|
||||
Self
|
||||
//~^ ERROR mismatched types
|
||||
//~| ERROR the constant `A` is not of type `i64`
|
||||
//~| ERROR the constant `B` is not of type `i64`
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
Outer::<1, 1>::o();
|
||||
//~^ ERROR no function or associated item named `o` found for struct `Outer` in the current scope
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:2:12
|
||||
|
|
||||
LL | #![feature(generic_const_exprs)]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error: the constant `A` is not of type `i64`
|
||||
--> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:6:38
|
||||
|
|
||||
LL | impl<const A: usize, const B: usize> Outer<A, B>
|
||||
| ^^^^^^^^^^^ expected `i64`, found `usize`
|
||||
|
|
||||
note: required by a bound in `Outer`
|
||||
--> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:5:14
|
||||
|
|
||||
LL | struct Outer<const A: i64, const B: i64>();
|
||||
| ^^^^^^^^^^^^ required by this bound in `Outer`
|
||||
|
||||
error: the constant `B` is not of type `i64`
|
||||
--> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:6:38
|
||||
|
|
||||
LL | impl<const A: usize, const B: usize> Outer<A, B>
|
||||
| ^^^^^^^^^^^ expected `i64`, found `usize`
|
||||
|
|
||||
note: required by a bound in `Outer`
|
||||
--> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:5:28
|
||||
|
|
||||
LL | struct Outer<const A: i64, const B: i64>();
|
||||
| ^^^^^^^^^^^^ required by this bound in `Outer`
|
||||
|
||||
error: the constant `A` is not of type `i64`
|
||||
--> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:14:15
|
||||
|
|
||||
LL | fn i() -> Self {
|
||||
| ^^^^ expected `i64`, found `usize`
|
||||
|
|
||||
note: required by a bound in `Outer`
|
||||
--> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:5:14
|
||||
|
|
||||
LL | struct Outer<const A: i64, const B: i64>();
|
||||
| ^^^^^^^^^^^^ required by this bound in `Outer`
|
||||
|
||||
error: the constant `B` is not of type `i64`
|
||||
--> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:14:15
|
||||
|
|
||||
LL | fn i() -> Self {
|
||||
| ^^^^ expected `i64`, found `usize`
|
||||
|
|
||||
note: required by a bound in `Outer`
|
||||
--> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:5:28
|
||||
|
|
||||
LL | struct Outer<const A: i64, const B: i64>();
|
||||
| ^^^^^^^^^^^^ required by this bound in `Outer`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:17:9
|
||||
|
|
||||
LL | struct Outer<const A: i64, const B: i64>();
|
||||
| ---------------------------------------- `Outer` defines a struct constructor here, which should be called
|
||||
...
|
||||
LL | fn i() -> Self {
|
||||
| ---- expected `Outer<A, B>` because of return type
|
||||
...
|
||||
LL | Self
|
||||
| ^^^^ expected `Outer<A, B>`, found struct constructor
|
||||
|
|
||||
= note: expected struct `Outer<A, B>`
|
||||
found struct constructor `fn() -> Outer<A, B> {Outer::<A, B>}`
|
||||
help: use parentheses to construct this tuple struct
|
||||
|
|
||||
LL | Self()
|
||||
| ++
|
||||
|
||||
error: the constant `A` is not of type `i64`
|
||||
--> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:17:9
|
||||
|
|
||||
LL | Self
|
||||
| ^^^^ expected `i64`, found `usize`
|
||||
|
|
||||
note: required by a bound in `Outer`
|
||||
--> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:5:14
|
||||
|
|
||||
LL | struct Outer<const A: i64, const B: i64>();
|
||||
| ^^^^^^^^^^^^ required by this bound in `Outer`
|
||||
|
||||
error: the constant `B` is not of type `i64`
|
||||
--> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:17:9
|
||||
|
|
||||
LL | Self
|
||||
| ^^^^ expected `i64`, found `usize`
|
||||
|
|
||||
note: required by a bound in `Outer`
|
||||
--> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:5:28
|
||||
|
|
||||
LL | struct Outer<const A: i64, const B: i64>();
|
||||
| ^^^^^^^^^^^^ required by this bound in `Outer`
|
||||
|
||||
error[E0599]: no function or associated item named `o` found for struct `Outer` in the current scope
|
||||
--> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:25:20
|
||||
|
|
||||
LL | struct Outer<const A: i64, const B: i64>();
|
||||
| ---------------------------------------- function or associated item `o` not found for this struct
|
||||
...
|
||||
LL | Outer::<1, 1>::o();
|
||||
| ^ function or associated item not found in `Outer<1, 1>`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:6:44
|
||||
|
|
||||
LL | impl<const A: usize, const B: usize> Outer<A, B>
|
||||
| ^ expected `i64`, found `usize`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:6:47
|
||||
|
|
||||
LL | impl<const A: usize, const B: usize> Outer<A, B>
|
||||
| ^ expected `i64`, found `usize`
|
||||
|
||||
error: aborting due to 10 previous errors; 1 warning emitted
|
||||
|
||||
Some errors have detailed explanations: E0308, E0599.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
//@ failure-status: 101
|
||||
//@ known-bug: unknown
|
||||
//@ known-bug: rust-lang/rust#125451
|
||||
//@ normalize-stderr-test "note: .*\n\n" -> ""
|
||||
//@ normalize-stderr-test "thread 'rustc' panicked.*\n.*\n" -> ""
|
||||
//@ normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: "
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
//@ revisions: old next
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@ check-pass
|
||||
|
||||
// The new trait solver does not return region constraints if the goal
|
||||
// is still ambiguous. This causes the following test to fail with ambiguity,
|
||||
// even though `(): LeakCheckFailure<'!a, V>` would return `'!a: 'static`
|
||||
// which would have caused a leak check failure.
|
||||
|
||||
trait Ambig {}
|
||||
impl Ambig for u32 {}
|
||||
impl Ambig for u16 {}
|
||||
|
||||
trait Id<T> {}
|
||||
impl Id<u32> for u32 {}
|
||||
impl Id<u16> for u16 {}
|
||||
|
||||
|
||||
trait LeakCheckFailure<'a, V: ?Sized> {}
|
||||
impl<V: ?Sized + Ambig> LeakCheckFailure<'static, V> for () {}
|
||||
|
||||
trait Trait<U, V> {}
|
||||
impl<V> Trait<u32, V> for () where for<'a> (): LeakCheckFailure<'a, V> {}
|
||||
impl<V> Trait<u16, V> for () {}
|
||||
fn impls_trait<T: Trait<U, V>, U: Id<V>, V>() {}
|
||||
fn main() {
|
||||
impls_trait::<(), _, _>()
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
error[E0283]: type annotations needed
|
||||
--> $DIR/leak-check-in-selection-6-ambig-unify.rs:30:5
|
||||
|
|
||||
LL | impls_trait::<(), _, _>()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_trait`
|
||||
|
|
||||
note: multiple `impl`s satisfying `(): Trait<_, _>` found
|
||||
--> $DIR/leak-check-in-selection-6-ambig-unify.rs:26:1
|
||||
|
|
||||
LL | impl<V> Trait<u32, V> for () where for<'b> (): LeakCheckFailure<'static, 'b, V> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | impl<V> Trait<u16, V> for () {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `impls_trait`
|
||||
--> $DIR/leak-check-in-selection-6-ambig-unify.rs:28:19
|
||||
|
|
||||
LL | fn impls_trait<T: Trait<U, V>, U: Id<V>, V>() {}
|
||||
| ^^^^^^^^^^^ required by this bound in `impls_trait`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0283`.
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
error[E0283]: type annotations needed
|
||||
--> $DIR/leak-check-in-selection-6-ambig-unify.rs:30:5
|
||||
|
|
||||
LL | impls_trait::<(), _, _>()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_trait`
|
||||
|
|
||||
note: multiple `impl`s satisfying `(): Trait<_, _>` found
|
||||
--> $DIR/leak-check-in-selection-6-ambig-unify.rs:26:1
|
||||
|
|
||||
LL | impl<V> Trait<u32, V> for () where for<'b> (): LeakCheckFailure<'static, 'b, V> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | impl<V> Trait<u16, V> for () {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `impls_trait`
|
||||
--> $DIR/leak-check-in-selection-6-ambig-unify.rs:28:19
|
||||
|
|
||||
LL | fn impls_trait<T: Trait<U, V>, U: Id<V>, V>() {}
|
||||
| ^^^^^^^^^^^ required by this bound in `impls_trait`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0283`.
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
//@ revisions: old next
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
|
||||
// The new trait solver does not return region constraints if the goal
|
||||
// is still ambiguous. This should cause the following test to fail with
|
||||
// ambiguity as even if `(): LeakCheckFailure<'static, '!b, V>` unifies
|
||||
// `'!b` with `'static`, we erase all region constraints.
|
||||
//
|
||||
// However, we do still unify the var_value for `'b` with `'static`,
|
||||
// causing us to return this requirement via the `var_values` even if
|
||||
// we don't return any region constraints. This is a bit inconsistent
|
||||
// but isn't something we should really worry about imo.
|
||||
trait Ambig {}
|
||||
impl Ambig for u32 {}
|
||||
impl Ambig for u16 {}
|
||||
|
||||
trait Id<T> {}
|
||||
impl Id<u32> for u32 {}
|
||||
impl Id<u16> for u16 {}
|
||||
|
||||
|
||||
trait LeakCheckFailure<'a, 'b, V: ?Sized> {}
|
||||
impl<'a, 'b: 'a, V: ?Sized + Ambig> LeakCheckFailure<'a, 'b, V> for () {}
|
||||
|
||||
trait Trait<U, V> {}
|
||||
impl<V> Trait<u32, V> for () where for<'b> (): LeakCheckFailure<'static, 'b, V> {}
|
||||
impl<V> Trait<u16, V> for () {}
|
||||
fn impls_trait<T: Trait<U, V>, U: Id<V>, V>() {}
|
||||
fn main() {
|
||||
impls_trait::<(), _, _>()
|
||||
//~^ ERROR type annotations needed
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
//@ check-pass
|
||||
//@ compile-flags: -Znext-solver
|
||||
//@ ignore-compare-mode-next-solver (explicitly enabled)
|
||||
|
||||
// Regression test for an ICE when trying to bootstrap rustc
|
||||
// with #125343. An ambiguous goal returned a `TypeOutlives`
|
||||
// constraint referencing an inference variable. This inference
|
||||
// variable was created inside of the goal, causing it to be
|
||||
// unconstrained in the caller. This then caused an ICE in MIR
|
||||
// borrowck.
|
||||
|
||||
struct Foo<T>(T);
|
||||
trait Extend<T> {
|
||||
fn extend<I: IntoIterator<Item = T>>(iter: I);
|
||||
}
|
||||
|
||||
impl<T> Extend<T> for Foo<T> {
|
||||
fn extend<I: IntoIterator<Item = T>>(_: I) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a + Copy> Extend<&'a T> for Foo<T> {
|
||||
fn extend<I: IntoIterator<Item = &'a T>>(iter: I) {
|
||||
<Self as Extend<T>>::extend(iter.into_iter().copied())
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue