Merge from rustc
This commit is contained in:
commit
0334bf8520
138 changed files with 2310 additions and 1057 deletions
|
@ -2961,6 +2961,7 @@ impl Item {
|
||||||
| ItemKind::GlobalAsm(_)
|
| ItemKind::GlobalAsm(_)
|
||||||
| ItemKind::MacCall(_)
|
| ItemKind::MacCall(_)
|
||||||
| ItemKind::Delegation(_)
|
| ItemKind::Delegation(_)
|
||||||
|
| ItemKind::DelegationMac(_)
|
||||||
| ItemKind::MacroDef(_) => None,
|
| ItemKind::MacroDef(_) => None,
|
||||||
ItemKind::Static(_) => None,
|
ItemKind::Static(_) => None,
|
||||||
ItemKind::Const(i) => Some(&i.generics),
|
ItemKind::Const(i) => Some(&i.generics),
|
||||||
|
@ -3123,8 +3124,16 @@ pub struct Delegation {
|
||||||
/// Path resolution id.
|
/// Path resolution id.
|
||||||
pub id: NodeId,
|
pub id: NodeId,
|
||||||
pub qself: Option<P<QSelf>>,
|
pub qself: Option<P<QSelf>>,
|
||||||
pub rename: Option<Ident>,
|
|
||||||
pub path: Path,
|
pub path: Path,
|
||||||
|
pub rename: Option<Ident>,
|
||||||
|
pub body: Option<P<Block>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||||
|
pub struct DelegationMac {
|
||||||
|
pub qself: Option<P<QSelf>>,
|
||||||
|
pub prefix: Path,
|
||||||
|
pub suffixes: ThinVec<(Ident, Option<Ident>)>,
|
||||||
pub body: Option<P<Block>>,
|
pub body: Option<P<Block>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3243,10 +3252,13 @@ pub enum ItemKind {
|
||||||
/// A macro definition.
|
/// A macro definition.
|
||||||
MacroDef(MacroDef),
|
MacroDef(MacroDef),
|
||||||
|
|
||||||
/// A delegation item (`reuse`).
|
/// A single delegation item (`reuse`).
|
||||||
///
|
///
|
||||||
/// E.g. `reuse <Type as Trait>::name { target_expr_template }`.
|
/// E.g. `reuse <Type as Trait>::name { target_expr_template }`.
|
||||||
Delegation(Box<Delegation>),
|
Delegation(Box<Delegation>),
|
||||||
|
/// A list delegation item (`reuse prefix::{a, b, c}`).
|
||||||
|
/// Treated similarly to a macro call and expanded early.
|
||||||
|
DelegationMac(Box<DelegationMac>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemKind {
|
impl ItemKind {
|
||||||
|
@ -3256,7 +3268,7 @@ impl ItemKind {
|
||||||
match self {
|
match self {
|
||||||
Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..)
|
Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..)
|
||||||
| Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..)
|
| Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..)
|
||||||
| Delegation(..) => "a",
|
| Delegation(..) | DelegationMac(..) => "a",
|
||||||
ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
|
ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3281,6 +3293,7 @@ impl ItemKind {
|
||||||
ItemKind::MacroDef(..) => "macro definition",
|
ItemKind::MacroDef(..) => "macro definition",
|
||||||
ItemKind::Impl { .. } => "implementation",
|
ItemKind::Impl { .. } => "implementation",
|
||||||
ItemKind::Delegation(..) => "delegated function",
|
ItemKind::Delegation(..) => "delegated function",
|
||||||
|
ItemKind::DelegationMac(..) => "delegation",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3324,6 +3337,8 @@ pub enum AssocItemKind {
|
||||||
MacCall(P<MacCall>),
|
MacCall(P<MacCall>),
|
||||||
/// An associated delegation item.
|
/// An associated delegation item.
|
||||||
Delegation(Box<Delegation>),
|
Delegation(Box<Delegation>),
|
||||||
|
/// An associated delegation item list.
|
||||||
|
DelegationMac(Box<DelegationMac>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AssocItemKind {
|
impl AssocItemKind {
|
||||||
|
@ -3332,7 +3347,9 @@ impl AssocItemKind {
|
||||||
Self::Const(box ConstItem { defaultness, .. })
|
Self::Const(box ConstItem { defaultness, .. })
|
||||||
| Self::Fn(box Fn { defaultness, .. })
|
| Self::Fn(box Fn { defaultness, .. })
|
||||||
| Self::Type(box TyAlias { defaultness, .. }) => defaultness,
|
| Self::Type(box TyAlias { defaultness, .. }) => defaultness,
|
||||||
Self::MacCall(..) | Self::Delegation(..) => Defaultness::Final,
|
Self::MacCall(..) | Self::Delegation(..) | Self::DelegationMac(..) => {
|
||||||
|
Defaultness::Final
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3345,6 +3362,7 @@ impl From<AssocItemKind> for ItemKind {
|
||||||
AssocItemKind::Type(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind),
|
AssocItemKind::Type(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind),
|
||||||
AssocItemKind::MacCall(a) => ItemKind::MacCall(a),
|
AssocItemKind::MacCall(a) => ItemKind::MacCall(a),
|
||||||
AssocItemKind::Delegation(delegation) => ItemKind::Delegation(delegation),
|
AssocItemKind::Delegation(delegation) => ItemKind::Delegation(delegation),
|
||||||
|
AssocItemKind::DelegationMac(delegation) => ItemKind::DelegationMac(delegation),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3359,6 +3377,7 @@ impl TryFrom<ItemKind> for AssocItemKind {
|
||||||
ItemKind::TyAlias(ty_kind) => AssocItemKind::Type(ty_kind),
|
ItemKind::TyAlias(ty_kind) => AssocItemKind::Type(ty_kind),
|
||||||
ItemKind::MacCall(a) => AssocItemKind::MacCall(a),
|
ItemKind::MacCall(a) => AssocItemKind::MacCall(a),
|
||||||
ItemKind::Delegation(d) => AssocItemKind::Delegation(d),
|
ItemKind::Delegation(d) => AssocItemKind::Delegation(d),
|
||||||
|
ItemKind::DelegationMac(d) => AssocItemKind::DelegationMac(d),
|
||||||
_ => return Err(item_kind),
|
_ => return Err(item_kind),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1170,6 +1170,19 @@ impl NoopVisitItemKind for ItemKind {
|
||||||
vis.visit_block(body);
|
vis.visit_block(body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
||||||
|
vis.visit_qself(qself);
|
||||||
|
vis.visit_path(prefix);
|
||||||
|
for (ident, rename) in suffixes {
|
||||||
|
vis.visit_ident(ident);
|
||||||
|
if let Some(rename) = rename {
|
||||||
|
vis.visit_ident(rename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(body) = body {
|
||||||
|
vis.visit_block(body);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1213,6 +1226,19 @@ impl NoopVisitItemKind for AssocItemKind {
|
||||||
visitor.visit_block(body);
|
visitor.visit_block(body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
||||||
|
visitor.visit_qself(qself);
|
||||||
|
visitor.visit_path(prefix);
|
||||||
|
for (ident, rename) in suffixes {
|
||||||
|
visitor.visit_ident(ident);
|
||||||
|
if let Some(rename) = rename {
|
||||||
|
visitor.visit_ident(rename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(body) = body {
|
||||||
|
visitor.visit_block(body);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -403,6 +403,19 @@ impl WalkItemKind for ItemKind {
|
||||||
visit_opt!(visitor, visit_ident, *rename);
|
visit_opt!(visitor, visit_ident, *rename);
|
||||||
visit_opt!(visitor, visit_block, body);
|
visit_opt!(visitor, visit_block, body);
|
||||||
}
|
}
|
||||||
|
ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
||||||
|
if let Some(qself) = qself {
|
||||||
|
try_visit!(visitor.visit_ty(&qself.ty));
|
||||||
|
}
|
||||||
|
try_visit!(visitor.visit_path(prefix, item.id));
|
||||||
|
for (ident, rename) in suffixes {
|
||||||
|
visitor.visit_ident(*ident);
|
||||||
|
if let Some(rename) = rename {
|
||||||
|
visitor.visit_ident(*rename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
visit_opt!(visitor, visit_block, body);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
V::Result::output()
|
V::Result::output()
|
||||||
}
|
}
|
||||||
|
@ -815,6 +828,19 @@ impl WalkItemKind for AssocItemKind {
|
||||||
visit_opt!(visitor, visit_ident, *rename);
|
visit_opt!(visitor, visit_ident, *rename);
|
||||||
visit_opt!(visitor, visit_block, body);
|
visit_opt!(visitor, visit_block, body);
|
||||||
}
|
}
|
||||||
|
AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
||||||
|
if let Some(qself) = qself {
|
||||||
|
try_visit!(visitor.visit_ty(&qself.ty));
|
||||||
|
}
|
||||||
|
try_visit!(visitor.visit_path(prefix, item.id));
|
||||||
|
for (ident, rename) in suffixes {
|
||||||
|
visitor.visit_ident(*ident);
|
||||||
|
if let Some(rename) = rename {
|
||||||
|
visitor.visit_ident(*rename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
visit_opt!(visitor, visit_block, body);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
V::Result::output()
|
V::Result::output()
|
||||||
}
|
}
|
||||||
|
|
|
@ -460,8 +460,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
delegation_results.body_id,
|
delegation_results.body_id,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ItemKind::MacCall(..) => {
|
ItemKind::MacCall(..) | ItemKind::DelegationMac(..) => {
|
||||||
panic!("`TyMac` should have been expanded by now")
|
panic!("macros should have been expanded by now")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -845,7 +845,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
);
|
);
|
||||||
(delegation_results.generics, item_kind, true)
|
(delegation_results.generics, item_kind, true)
|
||||||
}
|
}
|
||||||
AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"),
|
AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
|
||||||
|
panic!("macros should have been expanded by now")
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let item = hir::TraitItem {
|
let item = hir::TraitItem {
|
||||||
|
@ -869,7 +871,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
|
AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
|
||||||
has_self: self.delegation_has_self(i.id, delegation.id, i.span),
|
has_self: self.delegation_has_self(i.id, delegation.id, i.span),
|
||||||
},
|
},
|
||||||
AssocItemKind::MacCall(..) => unimplemented!(),
|
AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
|
||||||
|
panic!("macros should have been expanded by now")
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } };
|
let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } };
|
||||||
hir::TraitItemRef {
|
hir::TraitItemRef {
|
||||||
|
@ -964,7 +968,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
hir::ImplItemKind::Fn(delegation_results.sig, delegation_results.body_id),
|
hir::ImplItemKind::Fn(delegation_results.sig, delegation_results.body_id),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
AssocItemKind::MacCall(..) => panic!("`TyMac` should have been expanded by now"),
|
AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
|
||||||
|
panic!("macros should have been expanded by now")
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let item = hir::ImplItem {
|
let item = hir::ImplItem {
|
||||||
|
@ -993,7 +999,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
|
AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
|
||||||
has_self: self.delegation_has_self(i.id, delegation.id, i.span),
|
has_self: self.delegation_has_self(i.id, delegation.id, i.span),
|
||||||
},
|
},
|
||||||
AssocItemKind::MacCall(..) => unimplemented!(),
|
AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
|
||||||
|
panic!("macros should have been expanded by now")
|
||||||
|
}
|
||||||
},
|
},
|
||||||
trait_item_def_id: self
|
trait_item_def_id: self
|
||||||
.resolver
|
.resolver
|
||||||
|
|
|
@ -5,6 +5,7 @@ use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
|
||||||
use ast::StaticItem;
|
use ast::StaticItem;
|
||||||
use itertools::{Itertools, Position};
|
use itertools::{Itertools, Position};
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
|
use rustc_ast::ptr::P;
|
||||||
use rustc_ast::ModKind;
|
use rustc_ast::ModKind;
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
|
|
||||||
|
@ -374,9 +375,22 @@ impl<'a> State<'a> {
|
||||||
state.print_visibility(&item.vis)
|
state.print_visibility(&item.vis)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ast::ItemKind::Delegation(box delegation) => {
|
ast::ItemKind::Delegation(deleg) => self.print_delegation(
|
||||||
self.print_delegation(delegation, &item.vis, &item.attrs)
|
&item.attrs,
|
||||||
}
|
&item.vis,
|
||||||
|
&deleg.qself,
|
||||||
|
&deleg.path,
|
||||||
|
None,
|
||||||
|
&deleg.body,
|
||||||
|
),
|
||||||
|
ast::ItemKind::DelegationMac(deleg) => self.print_delegation(
|
||||||
|
&item.attrs,
|
||||||
|
&item.vis,
|
||||||
|
&deleg.qself,
|
||||||
|
&deleg.prefix,
|
||||||
|
Some(&deleg.suffixes),
|
||||||
|
&deleg.body,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
self.ann.post(self, AnnNode::Item(item))
|
self.ann.post(self, AnnNode::Item(item))
|
||||||
}
|
}
|
||||||
|
@ -553,31 +567,63 @@ impl<'a> State<'a> {
|
||||||
self.word(";");
|
self.word(";");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::AssocItemKind::Delegation(box delegation) => {
|
ast::AssocItemKind::Delegation(deleg) => self.print_delegation(
|
||||||
self.print_delegation(delegation, vis, &item.attrs)
|
&item.attrs,
|
||||||
}
|
vis,
|
||||||
|
&deleg.qself,
|
||||||
|
&deleg.path,
|
||||||
|
None,
|
||||||
|
&deleg.body,
|
||||||
|
),
|
||||||
|
ast::AssocItemKind::DelegationMac(deleg) => self.print_delegation(
|
||||||
|
&item.attrs,
|
||||||
|
vis,
|
||||||
|
&deleg.qself,
|
||||||
|
&deleg.prefix,
|
||||||
|
Some(&deleg.suffixes),
|
||||||
|
&deleg.body,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
self.ann.post(self, AnnNode::SubItem(id))
|
self.ann.post(self, AnnNode::SubItem(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn print_delegation(
|
pub(crate) fn print_delegation(
|
||||||
&mut self,
|
&mut self,
|
||||||
delegation: &ast::Delegation,
|
|
||||||
vis: &ast::Visibility,
|
|
||||||
attrs: &[ast::Attribute],
|
attrs: &[ast::Attribute],
|
||||||
|
vis: &ast::Visibility,
|
||||||
|
qself: &Option<P<ast::QSelf>>,
|
||||||
|
path: &ast::Path,
|
||||||
|
suffixes: Option<&[(Ident, Option<Ident>)]>,
|
||||||
|
body: &Option<P<ast::Block>>,
|
||||||
) {
|
) {
|
||||||
if delegation.body.is_some() {
|
if body.is_some() {
|
||||||
self.head("");
|
self.head("");
|
||||||
}
|
}
|
||||||
self.print_visibility(vis);
|
self.print_visibility(vis);
|
||||||
self.word_space("reuse");
|
self.word_nbsp("reuse");
|
||||||
|
|
||||||
if let Some(qself) = &delegation.qself {
|
if let Some(qself) = qself {
|
||||||
self.print_qpath(&delegation.path, qself, false);
|
self.print_qpath(path, qself, false);
|
||||||
} else {
|
} else {
|
||||||
self.print_path(&delegation.path, false, 0);
|
self.print_path(path, false, 0);
|
||||||
}
|
}
|
||||||
if let Some(body) = &delegation.body {
|
if let Some(suffixes) = suffixes {
|
||||||
|
self.word("::");
|
||||||
|
self.word("{");
|
||||||
|
for (i, (ident, rename)) in suffixes.iter().enumerate() {
|
||||||
|
self.print_ident(*ident);
|
||||||
|
if let Some(rename) = rename {
|
||||||
|
self.nbsp();
|
||||||
|
self.word_nbsp("as");
|
||||||
|
self.print_ident(*rename);
|
||||||
|
}
|
||||||
|
if i != suffixes.len() - 1 {
|
||||||
|
self.word_space(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.word("}");
|
||||||
|
}
|
||||||
|
if let Some(body) = body {
|
||||||
self.nbsp();
|
self.nbsp();
|
||||||
self.print_block_with_attrs(body, attrs);
|
self.print_block_with_attrs(body, attrs);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -207,13 +207,8 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
||||||
let cond_bitmap = coverage_context
|
let cond_bitmap = coverage_context
|
||||||
.try_get_mcdc_condition_bitmap(&instance, decision_depth)
|
.try_get_mcdc_condition_bitmap(&instance, decision_depth)
|
||||||
.expect("mcdc cond bitmap should have been allocated for merging into the global bitmap");
|
.expect("mcdc cond bitmap should have been allocated for merging into the global bitmap");
|
||||||
let bitmap_bytes = bx.tcx().coverage_ids_info(instance.def).mcdc_bitmap_bytes;
|
let bitmap_bytes = function_coverage_info.mcdc_bitmap_bytes;
|
||||||
assert!(bitmap_idx < bitmap_bytes, "bitmap index of the decision out of range");
|
assert!(bitmap_idx < bitmap_bytes, "bitmap index of the decision out of range");
|
||||||
assert!(
|
|
||||||
bitmap_bytes <= function_coverage_info.mcdc_bitmap_bytes,
|
|
||||||
"bitmap length disagreement: query says {bitmap_bytes} but function info only has {}",
|
|
||||||
function_coverage_info.mcdc_bitmap_bytes
|
|
||||||
);
|
|
||||||
|
|
||||||
let fn_name = bx.get_pgo_func_name_var(instance);
|
let fn_name = bx.get_pgo_func_name_var(instance);
|
||||||
let hash = bx.const_u64(function_coverage_info.function_source_hash);
|
let hash = bx.const_u64(function_coverage_info.function_source_hash);
|
||||||
|
|
|
@ -896,7 +896,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
||||||
style: SuggestionStyle,
|
style: SuggestionStyle,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
suggestion.sort_unstable();
|
suggestion.sort_unstable();
|
||||||
suggestion.dedup();
|
suggestion.dedup_by(|(s1, m1), (s2, m2)| s1.source_equal(*s2) && m1 == m2);
|
||||||
|
|
||||||
let parts = suggestion
|
let parts = suggestion
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
|
@ -106,6 +106,12 @@ impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::ExistentialTrait
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::UnevaluatedConst<I> {
|
||||||
|
fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
|
||||||
|
format!("{self:?}").into_diag_arg()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
into_diag_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize);
|
into_diag_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize);
|
||||||
|
|
||||||
impl IntoDiagArg for bool {
|
impl IntoDiagArg for bool {
|
||||||
|
|
|
@ -30,6 +30,9 @@ expand_duplicate_matcher_binding = duplicate matcher binding
|
||||||
.label = duplicate binding
|
.label = duplicate binding
|
||||||
.label2 = previous binding
|
.label2 = previous binding
|
||||||
|
|
||||||
|
expand_empty_delegation_list =
|
||||||
|
empty list delegation is not supported
|
||||||
|
|
||||||
expand_expected_paren_or_brace =
|
expand_expected_paren_or_brace =
|
||||||
expected `(` or `{"{"}`, found `{$token}`
|
expected `(` or `{"{"}`, found `{$token}`
|
||||||
|
|
||||||
|
|
|
@ -433,3 +433,10 @@ pub struct ExpectedParenOrBrace<'a> {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub token: Cow<'a, str>,
|
pub token: Cow<'a, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(expand_empty_delegation_list)]
|
||||||
|
pub(crate) struct EmptyDelegationList {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::base::*;
|
use crate::base::*;
|
||||||
use crate::config::StripUnconfigured;
|
use crate::config::StripUnconfigured;
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
IncompleteParse, RecursionLimitReached, RemoveExprNotSupported, RemoveNodeNotSupported,
|
EmptyDelegationList, IncompleteParse, RecursionLimitReached, RemoveExprNotSupported,
|
||||||
UnsupportedKeyValue, WrongFragmentKind,
|
RemoveNodeNotSupported, UnsupportedKeyValue, WrongFragmentKind,
|
||||||
};
|
};
|
||||||
use crate::mbe::diagnostics::annotate_err_with_kind;
|
use crate::mbe::diagnostics::annotate_err_with_kind;
|
||||||
use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod};
|
use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod};
|
||||||
|
@ -1041,6 +1041,7 @@ enum AddSemicolon {
|
||||||
trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
|
trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
|
||||||
type OutputTy = SmallVec<[Self; 1]>;
|
type OutputTy = SmallVec<[Self; 1]>;
|
||||||
type AttrsTy: Deref<Target = [ast::Attribute]> = ast::AttrVec;
|
type AttrsTy: Deref<Target = [ast::Attribute]> = ast::AttrVec;
|
||||||
|
type ItemKind = ItemKind;
|
||||||
const KIND: AstFragmentKind;
|
const KIND: AstFragmentKind;
|
||||||
fn to_annotatable(self) -> Annotatable;
|
fn to_annotatable(self) -> Annotatable;
|
||||||
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy;
|
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy;
|
||||||
|
@ -1059,6 +1060,18 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
|
||||||
fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
|
fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn delegation_item_kind(_deleg: Box<ast::Delegation>) -> Self::ItemKind {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
fn from_item(_item: ast::Item<Self::ItemKind>) -> Self {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
fn flatten_outputs(_outputs: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
fn pre_flat_map_node_collect_attr(_cfg: &StripUnconfigured<'_>, _attr: &ast::Attribute) {}
|
fn pre_flat_map_node_collect_attr(_cfg: &StripUnconfigured<'_>, _attr: &ast::Attribute) {}
|
||||||
fn post_flat_map_node_collect_bang(_output: &mut Self::OutputTy, _add_semicolon: AddSemicolon) {
|
fn post_flat_map_node_collect_bang(_output: &mut Self::OutputTy, _add_semicolon: AddSemicolon) {
|
||||||
}
|
}
|
||||||
|
@ -1106,6 +1119,21 @@ impl InvocationCollectorNode for P<ast::Item> {
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
|
||||||
|
match &self.kind {
|
||||||
|
ItemKind::DelegationMac(deleg) => Some((deleg, self)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {
|
||||||
|
ItemKind::Delegation(deleg)
|
||||||
|
}
|
||||||
|
fn from_item(item: ast::Item<Self::ItemKind>) -> Self {
|
||||||
|
P(item)
|
||||||
|
}
|
||||||
|
fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
|
||||||
|
items.flatten().collect()
|
||||||
|
}
|
||||||
fn wrap_flat_map_node_noop_flat_map(
|
fn wrap_flat_map_node_noop_flat_map(
|
||||||
mut node: Self,
|
mut node: Self,
|
||||||
collector: &mut InvocationCollector<'_, '_>,
|
collector: &mut InvocationCollector<'_, '_>,
|
||||||
|
@ -1214,6 +1242,7 @@ impl InvocationCollectorNode for P<ast::Item> {
|
||||||
struct TraitItemTag;
|
struct TraitItemTag;
|
||||||
impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag> {
|
impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag> {
|
||||||
type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
|
type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
|
||||||
|
type ItemKind = AssocItemKind;
|
||||||
const KIND: AstFragmentKind = AstFragmentKind::TraitItems;
|
const KIND: AstFragmentKind = AstFragmentKind::TraitItems;
|
||||||
fn to_annotatable(self) -> Annotatable {
|
fn to_annotatable(self) -> Annotatable {
|
||||||
Annotatable::TraitItem(self.wrapped)
|
Annotatable::TraitItem(self.wrapped)
|
||||||
|
@ -1234,11 +1263,27 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag>
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
|
||||||
|
match &self.wrapped.kind {
|
||||||
|
AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {
|
||||||
|
AssocItemKind::Delegation(deleg)
|
||||||
|
}
|
||||||
|
fn from_item(item: ast::Item<Self::ItemKind>) -> Self {
|
||||||
|
AstNodeWrapper::new(P(item), TraitItemTag)
|
||||||
|
}
|
||||||
|
fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
|
||||||
|
items.flatten().collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ImplItemTag;
|
struct ImplItemTag;
|
||||||
impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag> {
|
impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag> {
|
||||||
type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
|
type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
|
||||||
|
type ItemKind = AssocItemKind;
|
||||||
const KIND: AstFragmentKind = AstFragmentKind::ImplItems;
|
const KIND: AstFragmentKind = AstFragmentKind::ImplItems;
|
||||||
fn to_annotatable(self) -> Annotatable {
|
fn to_annotatable(self) -> Annotatable {
|
||||||
Annotatable::ImplItem(self.wrapped)
|
Annotatable::ImplItem(self.wrapped)
|
||||||
|
@ -1259,6 +1304,21 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
|
||||||
|
match &self.wrapped.kind {
|
||||||
|
AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {
|
||||||
|
AssocItemKind::Delegation(deleg)
|
||||||
|
}
|
||||||
|
fn from_item(item: ast::Item<Self::ItemKind>) -> Self {
|
||||||
|
AstNodeWrapper::new(P(item), ImplItemTag)
|
||||||
|
}
|
||||||
|
fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
|
||||||
|
items.flatten().collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InvocationCollectorNode for P<ast::ForeignItem> {
|
impl InvocationCollectorNode for P<ast::ForeignItem> {
|
||||||
|
@ -1420,6 +1480,24 @@ impl InvocationCollectorNode for ast::Stmt {
|
||||||
};
|
};
|
||||||
(mac, attrs, if add_semicolon { AddSemicolon::Yes } else { AddSemicolon::No })
|
(mac, attrs, if add_semicolon { AddSemicolon::Yes } else { AddSemicolon::No })
|
||||||
}
|
}
|
||||||
|
fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
|
||||||
|
match &self.kind {
|
||||||
|
StmtKind::Item(item) => match &item.kind {
|
||||||
|
ItemKind::DelegationMac(deleg) => Some((deleg, item)),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {
|
||||||
|
ItemKind::Delegation(deleg)
|
||||||
|
}
|
||||||
|
fn from_item(item: ast::Item<Self::ItemKind>) -> Self {
|
||||||
|
ast::Stmt { id: ast::DUMMY_NODE_ID, span: item.span, kind: StmtKind::Item(P(item)) }
|
||||||
|
}
|
||||||
|
fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
|
||||||
|
items.flatten().collect()
|
||||||
|
}
|
||||||
fn post_flat_map_node_collect_bang(stmts: &mut Self::OutputTy, add_semicolon: AddSemicolon) {
|
fn post_flat_map_node_collect_bang(stmts: &mut Self::OutputTy, add_semicolon: AddSemicolon) {
|
||||||
// If this is a macro invocation with a semicolon, then apply that
|
// If this is a macro invocation with a semicolon, then apply that
|
||||||
// semicolon to the final statement produced by expansion.
|
// semicolon to the final statement produced by expansion.
|
||||||
|
@ -1818,6 +1896,40 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
||||||
Node::post_flat_map_node_collect_bang(&mut res, add_semicolon);
|
Node::post_flat_map_node_collect_bang(&mut res, add_semicolon);
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
None if let Some((deleg, item)) = node.delegation_list() => {
|
||||||
|
if deleg.suffixes.is_empty() {
|
||||||
|
// Report an error for now, to avoid keeping stem for resolution and
|
||||||
|
// stability checks.
|
||||||
|
self.cx.dcx().emit_err(EmptyDelegationList { span: item.span });
|
||||||
|
}
|
||||||
|
|
||||||
|
Node::flatten_outputs(deleg.suffixes.iter().map(|&(ident, rename)| {
|
||||||
|
let mut path = deleg.prefix.clone();
|
||||||
|
path.segments.push(ast::PathSegment {
|
||||||
|
ident,
|
||||||
|
id: ast::DUMMY_NODE_ID,
|
||||||
|
args: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut item = Node::from_item(ast::Item {
|
||||||
|
attrs: item.attrs.clone(),
|
||||||
|
id: ast::DUMMY_NODE_ID,
|
||||||
|
span: ident.span,
|
||||||
|
vis: item.vis.clone(),
|
||||||
|
ident: rename.unwrap_or(ident),
|
||||||
|
kind: Node::delegation_item_kind(Box::new(ast::Delegation {
|
||||||
|
id: ast::DUMMY_NODE_ID,
|
||||||
|
qself: deleg.qself.clone(),
|
||||||
|
path,
|
||||||
|
rename,
|
||||||
|
body: deleg.body.clone(),
|
||||||
|
})),
|
||||||
|
tokens: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
assign_id!(self, item.node_id_mut(), || item.noop_flat_map(self))
|
||||||
|
}))
|
||||||
|
}
|
||||||
None => {
|
None => {
|
||||||
match Node::wrap_flat_map_node_noop_flat_map(node, self, |mut node, this| {
|
match Node::wrap_flat_map_node_noop_flat_map(node, self, |mut node, this| {
|
||||||
assign_id!(this, node.node_id_mut(), || node.noop_flat_map(this))
|
assign_id!(this, node.node_id_mut(), || node.noop_flat_map(this))
|
||||||
|
@ -1866,6 +1978,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
||||||
self.collect_bang(mac, Node::KIND).make_ast::<Node>()
|
self.collect_bang(mac, Node::KIND).make_ast::<Node>()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
None if node.delegation_list().is_some() => unreachable!(),
|
||||||
None => {
|
None => {
|
||||||
assign_id!(self, node.node_id_mut(), || node.noop_visit(self))
|
assign_id!(self, node.node_id_mut(), || node.noop_visit(self))
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ pub(crate) enum MetaVarExpr {
|
||||||
|
|
||||||
/// The length of the repetition at a particular depth, where 0 is the inner-most
|
/// The length of the repetition at a particular depth, where 0 is the inner-most
|
||||||
/// repetition. The `usize` is the depth.
|
/// repetition. The `usize` is the depth.
|
||||||
Length(usize),
|
Len(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MetaVarExpr {
|
impl MetaVarExpr {
|
||||||
|
@ -48,13 +48,13 @@ impl MetaVarExpr {
|
||||||
MetaVarExpr::Ignore(parse_ident(&mut iter, psess, ident.span)?)
|
MetaVarExpr::Ignore(parse_ident(&mut iter, psess, ident.span)?)
|
||||||
}
|
}
|
||||||
"index" => MetaVarExpr::Index(parse_depth(&mut iter, psess, ident.span)?),
|
"index" => MetaVarExpr::Index(parse_depth(&mut iter, psess, ident.span)?),
|
||||||
"length" => MetaVarExpr::Length(parse_depth(&mut iter, psess, ident.span)?),
|
"len" => MetaVarExpr::Len(parse_depth(&mut iter, psess, ident.span)?),
|
||||||
_ => {
|
_ => {
|
||||||
let err_msg = "unrecognized meta-variable expression";
|
let err_msg = "unrecognized meta-variable expression";
|
||||||
let mut err = psess.dcx.struct_span_err(ident.span, err_msg);
|
let mut err = psess.dcx.struct_span_err(ident.span, err_msg);
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
ident.span,
|
ident.span,
|
||||||
"supported expressions are count, ignore, index and length",
|
"supported expressions are count, ignore, index and len",
|
||||||
"",
|
"",
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
|
@ -68,7 +68,7 @@ impl MetaVarExpr {
|
||||||
pub(crate) fn ident(&self) -> Option<Ident> {
|
pub(crate) fn ident(&self) -> Option<Ident> {
|
||||||
match *self {
|
match *self {
|
||||||
MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(ident),
|
MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(ident),
|
||||||
MetaVarExpr::Index(..) | MetaVarExpr::Length(..) => None,
|
MetaVarExpr::Index(..) | MetaVarExpr::Len(..) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ fn parse_count<'psess>(
|
||||||
Ok(MetaVarExpr::Count(ident, depth))
|
Ok(MetaVarExpr::Count(ident, depth))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses the depth used by index(depth) and length(depth).
|
/// Parses the depth used by index(depth) and len(depth).
|
||||||
fn parse_depth<'psess>(
|
fn parse_depth<'psess>(
|
||||||
iter: &mut RefTokenTreeCursor<'_>,
|
iter: &mut RefTokenTreeCursor<'_>,
|
||||||
psess: &'psess ParseSess,
|
psess: &'psess ParseSess,
|
||||||
|
|
|
@ -357,7 +357,7 @@ fn parse_sep_and_kleene_op<'a>(
|
||||||
|
|
||||||
// `$$` or a meta-variable is the lhs of a macro but shouldn't.
|
// `$$` or a meta-variable is the lhs of a macro but shouldn't.
|
||||||
//
|
//
|
||||||
// For example, `macro_rules! foo { ( ${length()} ) => {} }`
|
// For example, `macro_rules! foo { ( ${len()} ) => {} }`
|
||||||
fn span_dollar_dollar_or_metavar_in_the_lhs_err(sess: &Session, token: &Token) {
|
fn span_dollar_dollar_or_metavar_in_the_lhs_err(sess: &Session, token: &Token) {
|
||||||
sess.dcx()
|
sess.dcx()
|
||||||
.span_err(token.span, format!("unexpected token: {}", pprust::token_to_string(token)));
|
.span_err(token.span, format!("unexpected token: {}", pprust::token_to_string(token)));
|
||||||
|
|
|
@ -685,14 +685,14 @@ fn transcribe_metavar_expr<'a>(
|
||||||
}
|
}
|
||||||
None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "index")),
|
None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "index")),
|
||||||
},
|
},
|
||||||
MetaVarExpr::Length(depth) => match repeats.iter().nth_back(depth) {
|
MetaVarExpr::Len(depth) => match repeats.iter().nth_back(depth) {
|
||||||
Some((_, length)) => {
|
Some((_, length)) => {
|
||||||
result.push(TokenTree::token_alone(
|
result.push(TokenTree::token_alone(
|
||||||
TokenKind::lit(token::Integer, sym::integer(*length), None),
|
TokenKind::lit(token::Integer, sym::integer(*length), None),
|
||||||
visited_span(),
|
visited_span(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "length")),
|
None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "len")),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -938,14 +938,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_conversion_methods(
|
pub fn get_conversion_methods_for_diagnostic(
|
||||||
&self,
|
&self,
|
||||||
span: Span,
|
span: Span,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
checked_ty: Ty<'tcx>,
|
checked_ty: Ty<'tcx>,
|
||||||
hir_id: hir::HirId,
|
hir_id: hir::HirId,
|
||||||
) -> Vec<AssocItem> {
|
) -> Vec<AssocItem> {
|
||||||
let methods = self.probe_for_return_type(
|
let methods = self.probe_for_return_type_for_diagnostic(
|
||||||
span,
|
span,
|
||||||
probe::Mode::MethodCall,
|
probe::Mode::MethodCall,
|
||||||
expected,
|
expected,
|
||||||
|
|
|
@ -2414,7 +2414,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
let guar = if field.name == kw::Empty {
|
let guar = if field.name == kw::Empty {
|
||||||
self.dcx().span_delayed_bug(field.span, "field name with no name")
|
self.dcx().span_delayed_bug(field.span, "field name with no name")
|
||||||
} else if self.method_exists(field, base_ty, expr.hir_id, expected.only_has_type(self)) {
|
} else if self.method_exists_for_diagnostic(
|
||||||
|
field,
|
||||||
|
base_ty,
|
||||||
|
expr.hir_id,
|
||||||
|
expected.only_has_type(self),
|
||||||
|
) {
|
||||||
self.ban_take_value_of_method(expr, base_ty, field)
|
self.ban_take_value_of_method(expr, base_ty, field)
|
||||||
} else if !base_ty.is_primitive_ty() {
|
} else if !base_ty.is_primitive_ty() {
|
||||||
self.ban_nonexisting_field(field, base, expr, base_ty)
|
self.ban_nonexisting_field(field, base, expr, base_ty)
|
||||||
|
@ -2600,7 +2605,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let mut err = self.private_field_err(field, base_did);
|
let mut err = self.private_field_err(field, base_did);
|
||||||
|
|
||||||
// Also check if an accessible method exists, which is often what is meant.
|
// Also check if an accessible method exists, which is often what is meant.
|
||||||
if self.method_exists(field, expr_t, expr.hir_id, return_ty)
|
if self.method_exists_for_diagnostic(field, expr_t, expr.hir_id, return_ty)
|
||||||
&& !self.expr_in_place(expr.hir_id)
|
&& !self.expr_in_place(expr.hir_id)
|
||||||
{
|
{
|
||||||
self.suggest_method_call(
|
self.suggest_method_call(
|
||||||
|
|
|
@ -18,12 +18,12 @@ use rustc_hir as hir;
|
||||||
use rustc_hir::def::{CtorOf, Res};
|
use rustc_hir::def::{CtorOf, Res};
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_hir::{HirId, PatKind};
|
use rustc_hir::{HirId, PatKind};
|
||||||
use rustc_middle::{bug, span_bug};
|
|
||||||
use rustc_middle::hir::place::ProjectionKind;
|
use rustc_middle::hir::place::ProjectionKind;
|
||||||
use rustc_middle::mir::FakeReadCause;
|
use rustc_middle::mir::FakeReadCause;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, adjustment, AdtKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _,
|
self, adjustment, AdtKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _,
|
||||||
};
|
};
|
||||||
|
use rustc_middle::{bug, span_bug};
|
||||||
use rustc_span::{ErrorGuaranteed, Span};
|
use rustc_span::{ErrorGuaranteed, Span};
|
||||||
use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
|
use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
|
||||||
use rustc_trait_selection::infer::InferCtxtExt;
|
use rustc_trait_selection::infer::InferCtxtExt;
|
||||||
|
@ -1181,6 +1181,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
||||||
debug!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat, first_ty);
|
debug!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat, first_ty);
|
||||||
return Ok(*first_ty);
|
return Ok(*first_ty);
|
||||||
}
|
}
|
||||||
|
} else if let PatKind::Ref(subpat, _) = pat.kind
|
||||||
|
&& self.cx.typeck_results().skipped_ref_pats().contains(pat.hir_id)
|
||||||
|
{
|
||||||
|
return self.pat_ty_adjusted(subpat);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.pat_ty_unadjusted(pat)
|
self.pat_ty_unadjusted(pat)
|
||||||
|
@ -1712,6 +1716,12 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
||||||
self.cat_pattern(place_with_id, subpat, op)?;
|
self.cat_pattern(place_with_id, subpat, op)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PatKind::Ref(subpat, _)
|
||||||
|
if self.cx.typeck_results().skipped_ref_pats().contains(pat.hir_id) =>
|
||||||
|
{
|
||||||
|
self.cat_pattern(place_with_id, subpat, op)?;
|
||||||
|
}
|
||||||
|
|
||||||
PatKind::Box(subpat) | PatKind::Ref(subpat, _) => {
|
PatKind::Box(subpat) | PatKind::Ref(subpat, _) => {
|
||||||
// box p1, &p1, &mut p1. we can ignore the mutability of
|
// box p1, &p1, &mut p1. we can ignore the mutability of
|
||||||
// PatKind::Ref since that information is already contained
|
// PatKind::Ref since that information is already contained
|
||||||
|
|
|
@ -290,7 +290,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
|
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let expr = expr.peel_blocks();
|
let expr = expr.peel_blocks();
|
||||||
let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
|
let methods =
|
||||||
|
self.get_conversion_methods_for_diagnostic(expr.span, expected, found, expr.hir_id);
|
||||||
|
|
||||||
if let Some((suggestion, msg, applicability, verbose, annotation)) =
|
if let Some((suggestion, msg, applicability, verbose, annotation)) =
|
||||||
self.suggest_deref_or_ref(expr, found, expected)
|
self.suggest_deref_or_ref(expr, found, expected)
|
||||||
|
|
|
@ -91,7 +91,7 @@ pub enum CandidateSource {
|
||||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
/// Determines whether the type `self_ty` supports a visible method named `method_name` or not.
|
/// Determines whether the type `self_ty` supports a visible method named `method_name` or not.
|
||||||
#[instrument(level = "debug", skip(self))]
|
#[instrument(level = "debug", skip(self))]
|
||||||
pub fn method_exists(
|
pub fn method_exists_for_diagnostic(
|
||||||
&self,
|
&self,
|
||||||
method_name: Ident,
|
method_name: Ident,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
|
@ -102,7 +102,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
probe::Mode::MethodCall,
|
probe::Mode::MethodCall,
|
||||||
method_name,
|
method_name,
|
||||||
return_type,
|
return_type,
|
||||||
IsSuggestion(false),
|
IsSuggestion(true),
|
||||||
self_ty,
|
self_ty,
|
||||||
call_expr_id,
|
call_expr_id,
|
||||||
ProbeScope::TraitsInScope,
|
ProbeScope::TraitsInScope,
|
||||||
|
|
|
@ -90,6 +90,11 @@ pub(crate) struct ProbeContext<'a, 'tcx> {
|
||||||
>,
|
>,
|
||||||
|
|
||||||
scope_expr_id: HirId,
|
scope_expr_id: HirId,
|
||||||
|
|
||||||
|
/// Is this probe being done for a diagnostic? This will skip some error reporting
|
||||||
|
/// machinery, since we don't particularly care about, for example, similarly named
|
||||||
|
/// candidates if we're *reporting* similarly named candidates.
|
||||||
|
is_suggestion: IsSuggestion,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> {
|
impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> {
|
||||||
|
@ -220,7 +225,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
/// would use to decide if a method is a plausible fit for
|
/// would use to decide if a method is a plausible fit for
|
||||||
/// ambiguity purposes).
|
/// ambiguity purposes).
|
||||||
#[instrument(level = "debug", skip(self, candidate_filter))]
|
#[instrument(level = "debug", skip(self, candidate_filter))]
|
||||||
pub fn probe_for_return_type(
|
pub fn probe_for_return_type_for_diagnostic(
|
||||||
&self,
|
&self,
|
||||||
span: Span,
|
span: Span,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
|
@ -459,6 +464,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
&orig_values,
|
&orig_values,
|
||||||
steps.steps,
|
steps.steps,
|
||||||
scope_expr_id,
|
scope_expr_id,
|
||||||
|
is_suggestion,
|
||||||
);
|
);
|
||||||
|
|
||||||
probe_cx.assemble_inherent_candidates();
|
probe_cx.assemble_inherent_candidates();
|
||||||
|
@ -553,6 +559,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
orig_steps_var_values: &'a OriginalQueryValues<'tcx>,
|
orig_steps_var_values: &'a OriginalQueryValues<'tcx>,
|
||||||
steps: &'tcx [CandidateStep<'tcx>],
|
steps: &'tcx [CandidateStep<'tcx>],
|
||||||
scope_expr_id: HirId,
|
scope_expr_id: HirId,
|
||||||
|
is_suggestion: IsSuggestion,
|
||||||
) -> ProbeContext<'a, 'tcx> {
|
) -> ProbeContext<'a, 'tcx> {
|
||||||
ProbeContext {
|
ProbeContext {
|
||||||
fcx,
|
fcx,
|
||||||
|
@ -570,6 +577,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
static_candidates: RefCell::new(Vec::new()),
|
static_candidates: RefCell::new(Vec::new()),
|
||||||
unsatisfied_predicates: RefCell::new(Vec::new()),
|
unsatisfied_predicates: RefCell::new(Vec::new()),
|
||||||
scope_expr_id,
|
scope_expr_id,
|
||||||
|
is_suggestion,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -944,6 +952,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If it's a `lookup_probe_for_diagnostic`, then quit early. No need to
|
||||||
|
// probe for other candidates.
|
||||||
|
if self.is_suggestion.0 {
|
||||||
|
return Err(MethodError::NoMatch(NoMatchData {
|
||||||
|
static_candidates: vec![],
|
||||||
|
unsatisfied_predicates: vec![],
|
||||||
|
out_of_scope_traits: vec![],
|
||||||
|
similar_candidate: None,
|
||||||
|
mode: self.mode,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
debug!("pick: actual search failed, assemble diagnostics");
|
debug!("pick: actual search failed, assemble diagnostics");
|
||||||
|
|
||||||
let static_candidates = std::mem::take(self.static_candidates.get_mut());
|
let static_candidates = std::mem::take(self.static_candidates.get_mut());
|
||||||
|
@ -1631,6 +1651,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
self.orig_steps_var_values,
|
self.orig_steps_var_values,
|
||||||
self.steps,
|
self.steps,
|
||||||
self.scope_expr_id,
|
self.scope_expr_id,
|
||||||
|
IsSuggestion(true),
|
||||||
);
|
);
|
||||||
pcx.allow_similar_names = true;
|
pcx.allow_similar_names = true;
|
||||||
pcx.assemble_inherent_candidates();
|
pcx.assemble_inherent_candidates();
|
||||||
|
|
|
@ -1143,7 +1143,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let label_span_not_found = |err: &mut Diag<'_>| {
|
let mut find_candidate_for_method = false;
|
||||||
|
|
||||||
|
let mut label_span_not_found = |err: &mut Diag<'_>| {
|
||||||
if unsatisfied_predicates.is_empty() {
|
if unsatisfied_predicates.is_empty() {
|
||||||
err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
|
err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
|
||||||
let is_string_or_ref_str = match rcvr_ty.kind() {
|
let is_string_or_ref_str = match rcvr_ty.kind() {
|
||||||
|
@ -1219,6 +1221,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
err.note(format!(
|
err.note(format!(
|
||||||
"the {item_kind} was found for\n{type_candidates}{additional_types}"
|
"the {item_kind} was found for\n{type_candidates}{additional_types}"
|
||||||
));
|
));
|
||||||
|
find_candidate_for_method = mode == Mode::MethodCall;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1371,9 +1374,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If an appropriate error source is not found, check method chain for possible candiates
|
|
||||||
if unsatisfied_predicates.is_empty()
|
if !find_candidate_for_method {
|
||||||
&& let Mode::MethodCall = mode
|
self.lookup_segments_chain_for_no_match_method(
|
||||||
|
&mut err,
|
||||||
|
item_name,
|
||||||
|
item_kind,
|
||||||
|
source,
|
||||||
|
no_match_data,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected);
|
||||||
|
Some(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If an appropriate error source is not found, check method chain for possible candidates
|
||||||
|
fn lookup_segments_chain_for_no_match_method(
|
||||||
|
&self,
|
||||||
|
err: &mut Diag<'_>,
|
||||||
|
item_name: Ident,
|
||||||
|
item_kind: &str,
|
||||||
|
source: SelfSource<'tcx>,
|
||||||
|
no_match_data: &NoMatchData<'tcx>,
|
||||||
|
) {
|
||||||
|
if no_match_data.unsatisfied_predicates.is_empty()
|
||||||
|
&& let Mode::MethodCall = no_match_data.mode
|
||||||
&& let SelfSource::MethodCall(mut source_expr) = source
|
&& let SelfSource::MethodCall(mut source_expr) = source
|
||||||
{
|
{
|
||||||
let mut stack_methods = vec![];
|
let mut stack_methods = vec![];
|
||||||
|
@ -1394,6 +1420,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
.unwrap_or(Ty::new_misc_error(self.tcx)),
|
.unwrap_or(Ty::new_misc_error(self.tcx)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// FIXME: `probe_for_name_many` searches for methods in inherent implementations,
|
||||||
|
// so it may return a candidate that doesn't belong to this `revr_ty`. We need to
|
||||||
|
// check whether the instantiated type matches the received one.
|
||||||
for _matched_method in self.probe_for_name_many(
|
for _matched_method in self.probe_for_name_many(
|
||||||
Mode::MethodCall,
|
Mode::MethodCall,
|
||||||
item_name,
|
item_name,
|
||||||
|
@ -1416,8 +1445,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected);
|
|
||||||
Some(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_likely_intended_associated_item(
|
fn find_likely_intended_associated_item(
|
||||||
|
@ -2814,7 +2841,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
Some(output_ty) => self.resolve_vars_if_possible(output_ty),
|
Some(output_ty) => self.resolve_vars_if_possible(output_ty),
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
let method_exists = self.method_exists(item_name, output_ty, call.hir_id, return_type);
|
let method_exists =
|
||||||
|
self.method_exists_for_diagnostic(item_name, output_ty, call.hir_id, return_type);
|
||||||
debug!("suggest_await_before_method: is_method_exist={}", method_exists);
|
debug!("suggest_await_before_method: is_method_exist={}", method_exists);
|
||||||
if method_exists {
|
if method_exists {
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
|
|
|
@ -347,5 +347,13 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di
|
||||||
"reduce the glob import's visibility or increase visibility of imported items",
|
"reduce the glob import's visibility or increase visibility of imported items",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
BuiltinLintDiag::MaybeTypo { span, name } => {
|
||||||
|
diag.span_suggestion_verbose(
|
||||||
|
span,
|
||||||
|
"an attribute with a similar name exists",
|
||||||
|
name,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -663,6 +663,10 @@ pub enum BuiltinLintDiag {
|
||||||
span: Span,
|
span: Span,
|
||||||
max_vis: String,
|
max_vis: String,
|
||||||
},
|
},
|
||||||
|
MaybeTypo {
|
||||||
|
span: Span,
|
||||||
|
name: Symbol,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lints that are buffered up early on in the `Session` before the
|
/// Lints that are buffered up early on in the `Session` before the
|
||||||
|
|
|
@ -129,17 +129,11 @@ pub enum CoverageKind {
|
||||||
/// Marks the point in MIR control flow represented by a evaluated condition.
|
/// Marks the point in MIR control flow represented by a evaluated condition.
|
||||||
///
|
///
|
||||||
/// This is eventually lowered to `llvm.instrprof.mcdc.condbitmap.update` in LLVM IR.
|
/// This is eventually lowered to `llvm.instrprof.mcdc.condbitmap.update` in LLVM IR.
|
||||||
///
|
|
||||||
/// If this statement does not survive MIR optimizations, the condition would never be
|
|
||||||
/// taken as evaluated.
|
|
||||||
CondBitmapUpdate { id: ConditionId, value: bool, decision_depth: u16 },
|
CondBitmapUpdate { id: ConditionId, value: bool, decision_depth: u16 },
|
||||||
|
|
||||||
/// Marks the point in MIR control flow represented by a evaluated decision.
|
/// Marks the point in MIR control flow represented by a evaluated decision.
|
||||||
///
|
///
|
||||||
/// This is eventually lowered to `llvm.instrprof.mcdc.tvbitmap.update` in LLVM IR.
|
/// This is eventually lowered to `llvm.instrprof.mcdc.tvbitmap.update` in LLVM IR.
|
||||||
///
|
|
||||||
/// If this statement does not survive MIR optimizations, the decision would never be
|
|
||||||
/// taken as evaluated.
|
|
||||||
TestVectorBitmapUpdate { bitmap_idx: u32, decision_depth: u16 },
|
TestVectorBitmapUpdate { bitmap_idx: u32, decision_depth: u16 },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -362,8 +362,4 @@ pub struct CoverageIdsInfo {
|
||||||
/// InstrumentCoverage MIR pass, if the highest-numbered counter increments
|
/// InstrumentCoverage MIR pass, if the highest-numbered counter increments
|
||||||
/// were removed by MIR optimizations.
|
/// were removed by MIR optimizations.
|
||||||
pub max_counter_id: mir::coverage::CounterId,
|
pub max_counter_id: mir::coverage::CounterId,
|
||||||
|
|
||||||
/// Coverage codegen for mcdc needs to know the size of the global bitmap so that it can
|
|
||||||
/// set the `bytemap-bytes` argument of the `llvm.instrprof.mcdc.tvbitmap.update` intrinsic.
|
|
||||||
pub mcdc_bitmap_bytes: u32,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1480,13 +1480,17 @@ pub enum BinOp {
|
||||||
BitOr,
|
BitOr,
|
||||||
/// The `<<` operator (shift left)
|
/// The `<<` operator (shift left)
|
||||||
///
|
///
|
||||||
/// The offset is truncated to the size of the first operand and made unsigned before shifting.
|
/// The offset is (uniquely) determined as follows:
|
||||||
|
/// - it is "equal modulo LHS::BITS" to the RHS
|
||||||
|
/// - it is in the range `0..LHS::BITS`
|
||||||
Shl,
|
Shl,
|
||||||
/// Like `Shl`, but is UB if the RHS >= LHS::BITS or RHS < 0
|
/// Like `Shl`, but is UB if the RHS >= LHS::BITS or RHS < 0
|
||||||
ShlUnchecked,
|
ShlUnchecked,
|
||||||
/// The `>>` operator (shift right)
|
/// The `>>` operator (shift right)
|
||||||
///
|
///
|
||||||
/// The offset is truncated to the size of the first operand and made unsigned before shifting.
|
/// The offset is (uniquely) determined as follows:
|
||||||
|
/// - it is "equal modulo LHS::BITS" to the RHS
|
||||||
|
/// - it is in the range `0..LHS::BITS`
|
||||||
///
|
///
|
||||||
/// This is an arithmetic shift if the LHS is signed
|
/// This is an arithmetic shift if the LHS is signed
|
||||||
/// and a logical shift if the LHS is unsigned.
|
/// and a logical shift if the LHS is unsigned.
|
||||||
|
|
|
@ -153,6 +153,8 @@ pub enum ProbeKind<'tcx> {
|
||||||
/// do a probe to find out what projection type(s) may be used to prove that
|
/// do a probe to find out what projection type(s) may be used to prove that
|
||||||
/// the source type upholds all of the target type's object bounds.
|
/// the source type upholds all of the target type's object bounds.
|
||||||
UpcastProjectionCompatibility,
|
UpcastProjectionCompatibility,
|
||||||
|
/// Looking for param-env candidates that satisfy the trait ref for a projection.
|
||||||
|
ShadowedEnvProbing,
|
||||||
/// Try to unify an opaque type with an existing key in the storage.
|
/// Try to unify an opaque type with an existing key in the storage.
|
||||||
OpaqueTypeStorageLookup { result: QueryResult<'tcx> },
|
OpaqueTypeStorageLookup { result: QueryResult<'tcx> },
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,6 +118,9 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
|
||||||
ProbeKind::TraitCandidate { source, result } => {
|
ProbeKind::TraitCandidate { source, result } => {
|
||||||
write!(self.f, "CANDIDATE {source:?}: {result:?}")
|
write!(self.f, "CANDIDATE {source:?}: {result:?}")
|
||||||
}
|
}
|
||||||
|
ProbeKind::ShadowedEnvProbing => {
|
||||||
|
write!(self.f, "PROBING FOR IMPLS SHADOWED BY PARAM-ENV CANDIDATE:")
|
||||||
|
}
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
self.nested(|this| {
|
self.nested(|this| {
|
||||||
|
|
|
@ -7,8 +7,7 @@ use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
|
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
|
||||||
use rustc_type_ir::ConstKind as IrConstKind;
|
use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
|
||||||
use rustc_type_ir::{TypeFlags, WithCachedTypeInfo};
|
|
||||||
|
|
||||||
mod int;
|
mod int;
|
||||||
mod kind;
|
mod kind;
|
||||||
|
@ -20,7 +19,8 @@ use rustc_span::Span;
|
||||||
use rustc_span::DUMMY_SP;
|
use rustc_span::DUMMY_SP;
|
||||||
pub use valtree::*;
|
pub use valtree::*;
|
||||||
|
|
||||||
pub type ConstKind<'tcx> = IrConstKind<TyCtxt<'tcx>>;
|
pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>;
|
||||||
|
pub type UnevaluatedConst<'tcx> = ir::UnevaluatedConst<TyCtxt<'tcx>>;
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "64")]
|
#[cfg(target_pointer_width = "64")]
|
||||||
rustc_data_structures::static_assert_size!(ConstKind<'_>, 32);
|
rustc_data_structures::static_assert_size!(ConstKind<'_>, 32);
|
||||||
|
@ -184,6 +184,14 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
|
||||||
Const::new_bound(tcx, debruijn, var, ty)
|
Const::new_bound(tcx, debruijn, var, ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_unevaluated(
|
||||||
|
interner: TyCtxt<'tcx>,
|
||||||
|
uv: ty::UnevaluatedConst<'tcx>,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
) -> Self {
|
||||||
|
Const::new_unevaluated(interner, uv, ty)
|
||||||
|
}
|
||||||
|
|
||||||
fn ty(self) -> Ty<'tcx> {
|
fn ty(self) -> Ty<'tcx> {
|
||||||
self.ty()
|
self.ty()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +1,15 @@
|
||||||
use super::Const;
|
use super::Const;
|
||||||
use crate::mir;
|
use crate::mir;
|
||||||
use crate::ty::abstract_const::CastKind;
|
use crate::ty::abstract_const::CastKind;
|
||||||
use crate::ty::GenericArgsRef;
|
|
||||||
use crate::ty::{self, visit::TypeVisitableExt as _, List, Ty, TyCtxt};
|
use crate::ty::{self, visit::TypeVisitableExt as _, List, Ty, TyCtxt};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
|
||||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
|
|
||||||
|
|
||||||
/// An unevaluated (potentially generic) constant used in the type-system.
|
#[extension(pub(crate) trait UnevaluatedConstEvalExt<'tcx>)]
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, TyEncodable, TyDecodable)]
|
impl<'tcx> ty::UnevaluatedConst<'tcx> {
|
||||||
#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
|
|
||||||
pub struct UnevaluatedConst<'tcx> {
|
|
||||||
pub def: DefId,
|
|
||||||
pub args: GenericArgsRef<'tcx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl rustc_errors::IntoDiagArg for UnevaluatedConst<'_> {
|
|
||||||
fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
|
|
||||||
format!("{self:?}").into_diag_arg()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> UnevaluatedConst<'tcx> {
|
|
||||||
/// FIXME(RalfJung): I cannot explain what this does or why it makes sense, but not doing this
|
/// FIXME(RalfJung): I cannot explain what this does or why it makes sense, but not doing this
|
||||||
/// hurts performance.
|
/// hurts performance.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn prepare_for_eval(
|
fn prepare_for_eval(
|
||||||
self,
|
self,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
@ -55,13 +40,6 @@ impl<'tcx> UnevaluatedConst<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> UnevaluatedConst<'tcx> {
|
|
||||||
#[inline]
|
|
||||||
pub fn new(def: DefId, args: GenericArgsRef<'tcx>) -> UnevaluatedConst<'tcx> {
|
|
||||||
UnevaluatedConst { def, args }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
#[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
|
#[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
|
||||||
pub enum Expr<'tcx> {
|
pub enum Expr<'tcx> {
|
||||||
|
|
|
@ -76,6 +76,7 @@ use rustc_type_ir::TyKind::*;
|
||||||
use rustc_type_ir::WithCachedTypeInfo;
|
use rustc_type_ir::WithCachedTypeInfo;
|
||||||
use rustc_type_ir::{CollectAndApply, Interner, TypeFlags};
|
use rustc_type_ir::{CollectAndApply, Interner, TypeFlags};
|
||||||
|
|
||||||
|
use std::assert_matches::assert_matches;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -91,67 +92,124 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||||
type DefiningOpaqueTypes = &'tcx ty::List<LocalDefId>;
|
type DefiningOpaqueTypes = &'tcx ty::List<LocalDefId>;
|
||||||
type AdtDef = ty::AdtDef<'tcx>;
|
type AdtDef = ty::AdtDef<'tcx>;
|
||||||
type GenericArgs = ty::GenericArgsRef<'tcx>;
|
type GenericArgs = ty::GenericArgsRef<'tcx>;
|
||||||
|
type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>];
|
||||||
type GenericArg = ty::GenericArg<'tcx>;
|
type GenericArg = ty::GenericArg<'tcx>;
|
||||||
type Term = ty::Term<'tcx>;
|
|
||||||
|
|
||||||
|
type Term = ty::Term<'tcx>;
|
||||||
type Binder<T: TypeVisitable<TyCtxt<'tcx>>> = Binder<'tcx, T>;
|
type Binder<T: TypeVisitable<TyCtxt<'tcx>>> = Binder<'tcx, T>;
|
||||||
type BoundVars = &'tcx List<ty::BoundVariableKind>;
|
type BoundVars = &'tcx List<ty::BoundVariableKind>;
|
||||||
type BoundVar = ty::BoundVariableKind;
|
type BoundVar = ty::BoundVariableKind;
|
||||||
type CanonicalVars = CanonicalVarInfos<'tcx>;
|
|
||||||
|
|
||||||
|
type CanonicalVars = CanonicalVarInfos<'tcx>;
|
||||||
type Ty = Ty<'tcx>;
|
type Ty = Ty<'tcx>;
|
||||||
type Tys = &'tcx List<Ty<'tcx>>;
|
type Tys = &'tcx List<Ty<'tcx>>;
|
||||||
type AliasTy = ty::AliasTy<'tcx>;
|
|
||||||
type ParamTy = ParamTy;
|
type ParamTy = ParamTy;
|
||||||
type BoundTy = ty::BoundTy;
|
type BoundTy = ty::BoundTy;
|
||||||
type PlaceholderTy = ty::PlaceholderType;
|
type PlaceholderTy = ty::PlaceholderType;
|
||||||
type ErrorGuaranteed = ErrorGuaranteed;
|
|
||||||
|
|
||||||
|
type ErrorGuaranteed = ErrorGuaranteed;
|
||||||
type BoundExistentialPredicates = &'tcx List<PolyExistentialPredicate<'tcx>>;
|
type BoundExistentialPredicates = &'tcx List<PolyExistentialPredicate<'tcx>>;
|
||||||
type PolyFnSig = PolyFnSig<'tcx>;
|
type PolyFnSig = PolyFnSig<'tcx>;
|
||||||
type AllocId = crate::mir::interpret::AllocId;
|
type AllocId = crate::mir::interpret::AllocId;
|
||||||
type Pat = Pattern<'tcx>;
|
|
||||||
|
|
||||||
|
type Pat = Pattern<'tcx>;
|
||||||
type Const = ty::Const<'tcx>;
|
type Const = ty::Const<'tcx>;
|
||||||
type AliasConst = ty::UnevaluatedConst<'tcx>;
|
type AliasConst = ty::UnevaluatedConst<'tcx>;
|
||||||
type PlaceholderConst = ty::PlaceholderConst;
|
type PlaceholderConst = ty::PlaceholderConst;
|
||||||
type ParamConst = ty::ParamConst;
|
type ParamConst = ty::ParamConst;
|
||||||
type BoundConst = ty::BoundVar;
|
type BoundConst = ty::BoundVar;
|
||||||
type ValueConst = ty::ValTree<'tcx>;
|
type ValueConst = ty::ValTree<'tcx>;
|
||||||
type ExprConst = ty::Expr<'tcx>;
|
|
||||||
|
|
||||||
|
type ExprConst = ty::Expr<'tcx>;
|
||||||
type Region = Region<'tcx>;
|
type Region = Region<'tcx>;
|
||||||
type EarlyParamRegion = ty::EarlyParamRegion;
|
type EarlyParamRegion = ty::EarlyParamRegion;
|
||||||
type LateParamRegion = ty::LateParamRegion;
|
type LateParamRegion = ty::LateParamRegion;
|
||||||
type BoundRegion = ty::BoundRegion;
|
type BoundRegion = ty::BoundRegion;
|
||||||
type InferRegion = ty::RegionVid;
|
type InferRegion = ty::RegionVid;
|
||||||
type PlaceholderRegion = ty::PlaceholderRegion;
|
|
||||||
|
|
||||||
|
type PlaceholderRegion = ty::PlaceholderRegion;
|
||||||
type Predicate = Predicate<'tcx>;
|
type Predicate = Predicate<'tcx>;
|
||||||
type TraitPredicate = ty::TraitPredicate<'tcx>;
|
type TraitPredicate = ty::TraitPredicate<'tcx>;
|
||||||
type RegionOutlivesPredicate = ty::RegionOutlivesPredicate<'tcx>;
|
type RegionOutlivesPredicate = ty::RegionOutlivesPredicate<'tcx>;
|
||||||
type TypeOutlivesPredicate = ty::TypeOutlivesPredicate<'tcx>;
|
type TypeOutlivesPredicate = ty::TypeOutlivesPredicate<'tcx>;
|
||||||
type ProjectionPredicate = ty::ProjectionPredicate<'tcx>;
|
type ProjectionPredicate = ty::ProjectionPredicate<'tcx>;
|
||||||
type AliasTerm = ty::AliasTerm<'tcx>;
|
|
||||||
type NormalizesTo = ty::NormalizesTo<'tcx>;
|
type NormalizesTo = ty::NormalizesTo<'tcx>;
|
||||||
type SubtypePredicate = ty::SubtypePredicate<'tcx>;
|
type SubtypePredicate = ty::SubtypePredicate<'tcx>;
|
||||||
type CoercePredicate = ty::CoercePredicate<'tcx>;
|
type CoercePredicate = ty::CoercePredicate<'tcx>;
|
||||||
type ClosureKind = ty::ClosureKind;
|
type ClosureKind = ty::ClosureKind;
|
||||||
type Clauses = ty::Clauses<'tcx>;
|
|
||||||
|
|
||||||
|
type Clauses = ty::Clauses<'tcx>;
|
||||||
fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars {
|
fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars {
|
||||||
self.mk_canonical_var_infos(infos)
|
self.mk_canonical_var_infos(infos)
|
||||||
}
|
}
|
||||||
|
|
||||||
type GenericsOf = &'tcx ty::Generics;
|
type GenericsOf = &'tcx ty::Generics;
|
||||||
|
|
||||||
fn generics_of(self, def_id: DefId) -> &'tcx ty::Generics {
|
fn generics_of(self, def_id: DefId) -> &'tcx ty::Generics {
|
||||||
self.generics_of(def_id)
|
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 alias_ty_kind(self, alias: ty::AliasTy<'tcx>) -> ty::AliasTyKind {
|
||||||
|
match self.def_kind(alias.def_id) {
|
||||||
|
DefKind::AssocTy => {
|
||||||
|
if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id))
|
||||||
|
{
|
||||||
|
ty::Inherent
|
||||||
|
} else {
|
||||||
|
ty::Projection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DefKind::OpaqueTy => ty::Opaque,
|
||||||
|
DefKind::TyAlias => ty::Weak,
|
||||||
|
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alias_term_kind(self, alias: ty::AliasTerm<'tcx>) -> ty::AliasTermKind {
|
||||||
|
match self.def_kind(alias.def_id) {
|
||||||
|
DefKind::AssocTy => {
|
||||||
|
if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id))
|
||||||
|
{
|
||||||
|
ty::AliasTermKind::InherentTy
|
||||||
|
} else {
|
||||||
|
ty::AliasTermKind::ProjectionTy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy,
|
||||||
|
DefKind::TyAlias => ty::AliasTermKind::WeakTy,
|
||||||
|
DefKind::AssocConst => ty::AliasTermKind::ProjectionConst,
|
||||||
|
DefKind::AnonConst => ty::AliasTermKind::UnevaluatedConst,
|
||||||
|
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trait_ref_and_own_args_for_alias(
|
||||||
|
self,
|
||||||
|
def_id: Self::DefId,
|
||||||
|
args: Self::GenericArgs,
|
||||||
|
) -> (rustc_type_ir::TraitRef<Self>, Self::GenericArgsSlice) {
|
||||||
|
assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst);
|
||||||
|
let trait_def_id = self.parent(def_id);
|
||||||
|
assert_matches!(self.def_kind(trait_def_id), DefKind::Trait);
|
||||||
|
let trait_generics = self.generics_of(trait_def_id);
|
||||||
|
(
|
||||||
|
ty::TraitRef::new(self, trait_def_id, args.truncate_to(self, trait_generics)),
|
||||||
|
&args[trait_generics.count()..],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs {
|
fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs {
|
||||||
self.mk_args(args)
|
self.mk_args(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mk_args_from_iter(self, args: impl Iterator<Item = Self::GenericArg>) -> Self::GenericArgs {
|
||||||
|
self.mk_args_from_iter(args)
|
||||||
|
}
|
||||||
|
|
||||||
fn check_and_mk_args(
|
fn check_and_mk_args(
|
||||||
self,
|
self,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
|
|
|
@ -96,9 +96,9 @@ pub use self::list::{List, ListWithCachedTypeInfo};
|
||||||
pub use self::parameterized::ParameterizedOverTcx;
|
pub use self::parameterized::ParameterizedOverTcx;
|
||||||
pub use self::pattern::{Pattern, PatternKind};
|
pub use self::pattern::{Pattern, PatternKind};
|
||||||
pub use self::predicate::{
|
pub use self::predicate::{
|
||||||
Clause, ClauseKind, CoercePredicate, ExistentialPredicate, ExistentialPredicateStableCmpExt,
|
AliasTerm, Clause, ClauseKind, CoercePredicate, ExistentialPredicate,
|
||||||
ExistentialProjection, ExistentialTraitRef, NormalizesTo, OutlivesPredicate,
|
ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef, NormalizesTo,
|
||||||
PolyCoercePredicate, PolyExistentialPredicate, PolyExistentialProjection,
|
OutlivesPredicate, PolyCoercePredicate, PolyExistentialPredicate, PolyExistentialProjection,
|
||||||
PolyExistentialTraitRef, PolyProjectionPredicate, PolyRegionOutlivesPredicate,
|
PolyExistentialTraitRef, PolyProjectionPredicate, PolyRegionOutlivesPredicate,
|
||||||
PolySubtypePredicate, PolyTraitPredicate, PolyTraitRef, PolyTypeOutlivesPredicate, Predicate,
|
PolySubtypePredicate, PolyTraitPredicate, PolyTraitRef, PolyTypeOutlivesPredicate, Predicate,
|
||||||
PredicateKind, ProjectionPredicate, RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef,
|
PredicateKind, ProjectionPredicate, RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef,
|
||||||
|
@ -110,11 +110,11 @@ pub use self::region::{
|
||||||
};
|
};
|
||||||
pub use self::rvalue_scopes::RvalueScopes;
|
pub use self::rvalue_scopes::RvalueScopes;
|
||||||
pub use self::sty::{
|
pub use self::sty::{
|
||||||
AliasTerm, AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind,
|
AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig,
|
||||||
CanonicalPolyFnSig, ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts,
|
ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, CoroutineClosureArgs,
|
||||||
CoroutineClosureArgs, CoroutineClosureArgsParts, CoroutineClosureSignature, FnSig, GenSig,
|
CoroutineClosureArgsParts, CoroutineClosureSignature, FnSig, GenSig, InlineConstArgs,
|
||||||
InlineConstArgs, InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut,
|
InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs,
|
||||||
UpvarArgs, VarianceDiagInfo,
|
VarianceDiagInfo,
|
||||||
};
|
};
|
||||||
pub use self::trait_def::TraitDef;
|
pub use self::trait_def::TraitDef;
|
||||||
pub use self::typeck_results::{
|
pub use self::typeck_results::{
|
||||||
|
|
|
@ -13,6 +13,7 @@ use crate::ty::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type TraitRef<'tcx> = ir::TraitRef<TyCtxt<'tcx>>;
|
pub type TraitRef<'tcx> = ir::TraitRef<TyCtxt<'tcx>>;
|
||||||
|
pub type AliasTerm<'tcx> = ir::AliasTerm<TyCtxt<'tcx>>;
|
||||||
pub type ProjectionPredicate<'tcx> = ir::ProjectionPredicate<TyCtxt<'tcx>>;
|
pub type ProjectionPredicate<'tcx> = ir::ProjectionPredicate<TyCtxt<'tcx>>;
|
||||||
pub type ExistentialPredicate<'tcx> = ir::ExistentialPredicate<TyCtxt<'tcx>>;
|
pub type ExistentialPredicate<'tcx> = ir::ExistentialPredicate<TyCtxt<'tcx>>;
|
||||||
pub type ExistentialTraitRef<'tcx> = ir::ExistentialTraitRef<TyCtxt<'tcx>>;
|
pub type ExistentialTraitRef<'tcx> = ir::ExistentialTraitRef<TyCtxt<'tcx>>;
|
||||||
|
|
|
@ -3038,6 +3038,33 @@ define_print! {
|
||||||
p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path()))
|
p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ty::AliasTy<'tcx> {
|
||||||
|
let alias_term: ty::AliasTerm<'tcx> = (*self).into();
|
||||||
|
p!(print(alias_term))
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::AliasTerm<'tcx> {
|
||||||
|
match self.kind(cx.tcx()) {
|
||||||
|
ty::AliasTermKind::InherentTy => p!(pretty_print_inherent_projection(*self)),
|
||||||
|
ty::AliasTermKind::ProjectionTy
|
||||||
|
| ty::AliasTermKind::WeakTy
|
||||||
|
| ty::AliasTermKind::OpaqueTy
|
||||||
|
| ty::AliasTermKind::UnevaluatedConst
|
||||||
|
| ty::AliasTermKind::ProjectionConst => {
|
||||||
|
// If we're printing verbosely, or don't want to invoke queries
|
||||||
|
// (`is_impl_trait_in_trait`), then fall back to printing the def path.
|
||||||
|
// This is likely what you want if you're debugging the compiler anyways.
|
||||||
|
if !(cx.should_print_verbose() || with_reduced_queries())
|
||||||
|
&& cx.tcx().is_impl_trait_in_trait(self.def_id)
|
||||||
|
{
|
||||||
|
return cx.pretty_print_opaque_impl_type(self.def_id, self.args);
|
||||||
|
} else {
|
||||||
|
p!(print_def_path(self.def_id, self.args));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ty::TraitPredicate<'tcx> {
|
ty::TraitPredicate<'tcx> {
|
||||||
p!(print(self.trait_ref.self_ty()), ": ");
|
p!(print(self.trait_ref.self_ty()), ": ");
|
||||||
p!(pretty_print_bound_constness(self.trait_ref));
|
p!(pretty_print_bound_constness(self.trait_ref));
|
||||||
|
@ -3205,33 +3232,6 @@ define_print_and_forward_display! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::AliasTy<'tcx> {
|
|
||||||
let alias_term: ty::AliasTerm<'tcx> = (*self).into();
|
|
||||||
p!(print(alias_term))
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::AliasTerm<'tcx> {
|
|
||||||
match self.kind(cx.tcx()) {
|
|
||||||
ty::AliasTermKind::InherentTy => p!(pretty_print_inherent_projection(*self)),
|
|
||||||
ty::AliasTermKind::ProjectionTy
|
|
||||||
| ty::AliasTermKind::WeakTy
|
|
||||||
| ty::AliasTermKind::OpaqueTy
|
|
||||||
| ty::AliasTermKind::UnevaluatedConst
|
|
||||||
| ty::AliasTermKind::ProjectionConst => {
|
|
||||||
// If we're printing verbosely, or don't want to invoke queries
|
|
||||||
// (`is_impl_trait_in_trait`), then fall back to printing the def path.
|
|
||||||
// This is likely what you want if you're debugging the compiler anyways.
|
|
||||||
if !(cx.should_print_verbose() || with_reduced_queries())
|
|
||||||
&& cx.tcx().is_impl_trait_in_trait(self.def_id)
|
|
||||||
{
|
|
||||||
return cx.pretty_print_opaque_impl_type(self.def_id, self.args);
|
|
||||||
} else {
|
|
||||||
p!(print_def_path(self.def_id, self.args));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::Predicate<'tcx> {
|
ty::Predicate<'tcx> {
|
||||||
p!(print(self.kind()))
|
p!(print(self.kind()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::mir::interpret;
|
||||||
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
|
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
|
||||||
use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
|
use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
|
||||||
use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
||||||
use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
|
use crate::ty::{self, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
|
||||||
use rustc_ast_ir::try_visit;
|
use rustc_ast_ir::try_visit;
|
||||||
use rustc_ast_ir::visit::VisitorResult;
|
use rustc_ast_ir::visit::VisitorResult;
|
||||||
use rustc_hir::def::Namespace;
|
use rustc_hir::def::Namespace;
|
||||||
|
@ -164,23 +164,6 @@ impl<'tcx> fmt::Debug for ty::Clause<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> fmt::Debug for AliasTy<'tcx> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
WithInfcx::with_no_infcx(self).fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTy<'tcx> {
|
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
|
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
|
||||||
f: &mut core::fmt::Formatter<'_>,
|
|
||||||
) -> core::fmt::Result {
|
|
||||||
f.debug_struct("AliasTy")
|
|
||||||
.field("args", &this.map(|data| data.args))
|
|
||||||
.field("def_id", &this.data.def_id)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Pattern<'tcx> {
|
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Pattern<'tcx> {
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
|
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
this: WithInfcx<'_, Infcx, &Self>,
|
||||||
|
@ -230,23 +213,6 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> fmt::Debug for ty::UnevaluatedConst<'tcx> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
WithInfcx::with_no_infcx(self).fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::UnevaluatedConst<'tcx> {
|
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
|
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
|
||||||
f: &mut core::fmt::Formatter<'_>,
|
|
||||||
) -> core::fmt::Result {
|
|
||||||
f.debug_struct("UnevaluatedConst")
|
|
||||||
.field("def", &this.data.def)
|
|
||||||
.field("args", &this.wrap(this.data.args))
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> fmt::Debug for ty::Const<'tcx> {
|
impl<'tcx> fmt::Debug for ty::Const<'tcx> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
WithInfcx::with_no_infcx(self).fmt(f)
|
WithInfcx::with_no_infcx(self).fmt(f)
|
||||||
|
|
|
@ -28,20 +28,17 @@ use std::iter;
|
||||||
use std::ops::{ControlFlow, Deref, Range};
|
use std::ops::{ControlFlow, Deref, Range};
|
||||||
use ty::util::IntTypeExt;
|
use ty::util::IntTypeExt;
|
||||||
|
|
||||||
use rustc_type_ir::BoundVar;
|
|
||||||
use rustc_type_ir::CollectAndApply;
|
|
||||||
use rustc_type_ir::DynKind;
|
|
||||||
use rustc_type_ir::TyKind as IrTyKind;
|
|
||||||
use rustc_type_ir::TyKind::*;
|
use rustc_type_ir::TyKind::*;
|
||||||
use rustc_type_ir::TypeAndMut as IrTypeAndMut;
|
use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind};
|
||||||
|
|
||||||
use super::fold::FnMutDelegate;
|
use super::fold::FnMutDelegate;
|
||||||
use super::GenericParamDefKind;
|
use super::GenericParamDefKind;
|
||||||
|
|
||||||
// Re-export and re-parameterize some `I = TyCtxt<'tcx>` types here
|
// Re-export and re-parameterize some `I = TyCtxt<'tcx>` types here
|
||||||
#[rustc_diagnostic_item = "TyKind"]
|
#[rustc_diagnostic_item = "TyKind"]
|
||||||
pub type TyKind<'tcx> = IrTyKind<TyCtxt<'tcx>>;
|
pub type TyKind<'tcx> = ir::TyKind<TyCtxt<'tcx>>;
|
||||||
pub type TypeAndMut<'tcx> = IrTypeAndMut<TyCtxt<'tcx>>;
|
pub type TypeAndMut<'tcx> = ir::TypeAndMut<TyCtxt<'tcx>>;
|
||||||
|
pub type AliasTy<'tcx> = ir::AliasTy<TyCtxt<'tcx>>;
|
||||||
|
|
||||||
pub trait Article {
|
pub trait Article {
|
||||||
fn article(&self) -> &'static str;
|
fn article(&self) -> &'static str;
|
||||||
|
@ -1105,371 +1102,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the unprojected term of a projection goal.
|
|
||||||
///
|
|
||||||
/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
|
|
||||||
/// * For an inherent projection, this would be `Ty::N<...>`.
|
|
||||||
/// * For an opaque type, there is no explicit syntax.
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
|
||||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
|
||||||
pub struct AliasTerm<'tcx> {
|
|
||||||
/// The parameters of the associated or opaque item.
|
|
||||||
///
|
|
||||||
/// For a projection, these are the generic parameters for the trait and the
|
|
||||||
/// GAT parameters, if there are any.
|
|
||||||
///
|
|
||||||
/// For an inherent projection, they consist of the self type and the GAT parameters,
|
|
||||||
/// if there are any.
|
|
||||||
///
|
|
||||||
/// For RPIT the generic parameters are for the generics of the function,
|
|
||||||
/// while for TAIT it is used for the generic parameters of the alias.
|
|
||||||
pub args: GenericArgsRef<'tcx>,
|
|
||||||
|
|
||||||
/// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether
|
|
||||||
/// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if
|
|
||||||
/// this is an opaque.
|
|
||||||
///
|
|
||||||
/// During codegen, `tcx.type_of(def_id)` can be used to get the type of the
|
|
||||||
/// underlying type if the type is an opaque.
|
|
||||||
///
|
|
||||||
/// Note that if this is an associated type, this is not the `DefId` of the
|
|
||||||
/// `TraitRef` containing this associated type, which is in `tcx.associated_item(def_id).container`,
|
|
||||||
/// aka. `tcx.parent(def_id)`.
|
|
||||||
pub def_id: DefId,
|
|
||||||
|
|
||||||
/// This field exists to prevent the creation of `AliasTerm` without using
|
|
||||||
/// [AliasTerm::new].
|
|
||||||
_use_alias_term_new_instead: (),
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Remove these when we uplift `AliasTerm`
|
|
||||||
use crate::ty::{DebugWithInfcx, InferCtxtLike, WithInfcx};
|
|
||||||
impl<'tcx> std::fmt::Debug for AliasTerm<'tcx> {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
WithInfcx::with_no_infcx(self).fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTerm<'tcx> {
|
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
|
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
|
||||||
f: &mut std::fmt::Formatter<'_>,
|
|
||||||
) -> std::fmt::Result {
|
|
||||||
f.debug_struct("AliasTerm")
|
|
||||||
.field("args", &this.map(|data| data.args))
|
|
||||||
.field("def_id", &this.data.def_id)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> rustc_type_ir::inherent::AliasTerm<TyCtxt<'tcx>> for AliasTerm<'tcx> {
|
|
||||||
fn new(
|
|
||||||
interner: TyCtxt<'tcx>,
|
|
||||||
trait_def_id: DefId,
|
|
||||||
args: impl IntoIterator<Item: Into<ty::GenericArg<'tcx>>>,
|
|
||||||
) -> Self {
|
|
||||||
AliasTerm::new(interner, trait_def_id, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn def_id(self) -> DefId {
|
|
||||||
self.def_id
|
|
||||||
}
|
|
||||||
|
|
||||||
fn args(self) -> ty::GenericArgsRef<'tcx> {
|
|
||||||
self.args
|
|
||||||
}
|
|
||||||
|
|
||||||
fn trait_def_id(self, interner: TyCtxt<'tcx>) -> DefId {
|
|
||||||
self.trait_def_id(interner)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn self_ty(self) -> Ty<'tcx> {
|
|
||||||
self.self_ty()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
|
|
||||||
self.with_self_ty(tcx, self_ty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> AliasTerm<'tcx> {
|
|
||||||
pub fn new(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
def_id: DefId,
|
|
||||||
args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
|
|
||||||
) -> AliasTerm<'tcx> {
|
|
||||||
let args = tcx.check_and_mk_args(def_id, args);
|
|
||||||
AliasTerm { def_id, args, _use_alias_term_new_instead: () }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn expect_ty(self, tcx: TyCtxt<'tcx>) -> AliasTy<'tcx> {
|
|
||||||
match self.kind(tcx) {
|
|
||||||
ty::AliasTermKind::ProjectionTy
|
|
||||||
| ty::AliasTermKind::InherentTy
|
|
||||||
| ty::AliasTermKind::OpaqueTy
|
|
||||||
| ty::AliasTermKind::WeakTy => {}
|
|
||||||
ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => {
|
|
||||||
bug!("Cannot turn `UnevaluatedConst` into `AliasTy`")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasTermKind {
|
|
||||||
match tcx.def_kind(self.def_id) {
|
|
||||||
DefKind::AssocTy => {
|
|
||||||
if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) {
|
|
||||||
ty::AliasTermKind::InherentTy
|
|
||||||
} else {
|
|
||||||
ty::AliasTermKind::ProjectionTy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy,
|
|
||||||
DefKind::TyAlias => ty::AliasTermKind::WeakTy,
|
|
||||||
DefKind::AnonConst => ty::AliasTermKind::UnevaluatedConst,
|
|
||||||
DefKind::AssocConst => ty::AliasTermKind::ProjectionConst,
|
|
||||||
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The following methods work only with (trait) associated item projections.
|
|
||||||
impl<'tcx> AliasTerm<'tcx> {
|
|
||||||
pub fn self_ty(self) -> Ty<'tcx> {
|
|
||||||
self.args.type_at(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
|
|
||||||
AliasTerm::new(
|
|
||||||
tcx,
|
|
||||||
self.def_id,
|
|
||||||
[self_ty.into()].into_iter().chain(self.args.iter().skip(1)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
|
|
||||||
match tcx.def_kind(self.def_id) {
|
|
||||||
DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id),
|
|
||||||
kind => bug!("expected a projection AliasTy; found {kind:?}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extracts the underlying trait reference from this projection.
|
|
||||||
/// For example, if this is a projection of `<T as Iterator>::Item`,
|
|
||||||
/// then this function would return a `T: Iterator` trait reference.
|
|
||||||
///
|
|
||||||
/// NOTE: This will drop the args for generic associated types
|
|
||||||
/// consider calling [Self::trait_ref_and_own_args] to get those
|
|
||||||
/// as well.
|
|
||||||
pub fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
|
|
||||||
let def_id = self.trait_def_id(tcx);
|
|
||||||
ty::TraitRef::new(tcx, def_id, self.args.truncate_to(tcx, tcx.generics_of(def_id)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extracts the underlying trait reference and own args from this projection.
|
|
||||||
/// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
|
|
||||||
/// then this function would return a `T: StreamingIterator` trait reference and `['a]` as the own args
|
|
||||||
pub fn trait_ref_and_own_args(
|
|
||||||
self,
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
|
|
||||||
let trait_def_id = self.trait_def_id(tcx);
|
|
||||||
let trait_generics = tcx.generics_of(trait_def_id);
|
|
||||||
(
|
|
||||||
ty::TraitRef::new(tcx, trait_def_id, self.args.truncate_to(tcx, trait_generics)),
|
|
||||||
&self.args[trait_generics.count()..],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_term(self, tcx: TyCtxt<'tcx>) -> ty::Term<'tcx> {
|
|
||||||
match self.kind(tcx) {
|
|
||||||
ty::AliasTermKind::ProjectionTy => Ty::new_alias(
|
|
||||||
tcx,
|
|
||||||
ty::Projection,
|
|
||||||
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
ty::AliasTermKind::InherentTy => Ty::new_alias(
|
|
||||||
tcx,
|
|
||||||
ty::Inherent,
|
|
||||||
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
ty::AliasTermKind::OpaqueTy => Ty::new_alias(
|
|
||||||
tcx,
|
|
||||||
ty::Opaque,
|
|
||||||
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
ty::AliasTermKind::WeakTy => Ty::new_alias(
|
|
||||||
tcx,
|
|
||||||
ty::Weak,
|
|
||||||
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => {
|
|
||||||
ty::Const::new_unevaluated(
|
|
||||||
tcx,
|
|
||||||
ty::UnevaluatedConst::new(self.def_id, self.args),
|
|
||||||
tcx.type_of(self.def_id).instantiate(tcx, self.args),
|
|
||||||
)
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> From<AliasTy<'tcx>> for AliasTerm<'tcx> {
|
|
||||||
fn from(ty: AliasTy<'tcx>) -> Self {
|
|
||||||
AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> From<ty::UnevaluatedConst<'tcx>> for AliasTerm<'tcx> {
|
|
||||||
fn from(ct: ty::UnevaluatedConst<'tcx>) -> Self {
|
|
||||||
AliasTerm { args: ct.args, def_id: ct.def, _use_alias_term_new_instead: () }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents the projection of an associated, opaque, or lazy-type-alias type.
|
|
||||||
///
|
|
||||||
/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
|
|
||||||
/// * For an inherent projection, this would be `Ty::N<...>`.
|
|
||||||
/// * For an opaque type, there is no explicit syntax.
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
|
||||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
|
||||||
pub struct AliasTy<'tcx> {
|
|
||||||
/// The parameters of the associated or opaque type.
|
|
||||||
///
|
|
||||||
/// For a projection, these are the generic parameters for the trait and the
|
|
||||||
/// GAT parameters, if there are any.
|
|
||||||
///
|
|
||||||
/// For an inherent projection, they consist of the self type and the GAT parameters,
|
|
||||||
/// if there are any.
|
|
||||||
///
|
|
||||||
/// For RPIT the generic parameters are for the generics of the function,
|
|
||||||
/// while for TAIT it is used for the generic parameters of the alias.
|
|
||||||
pub args: GenericArgsRef<'tcx>,
|
|
||||||
|
|
||||||
/// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether
|
|
||||||
/// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if
|
|
||||||
/// this is an opaque.
|
|
||||||
///
|
|
||||||
/// During codegen, `tcx.type_of(def_id)` can be used to get the type of the
|
|
||||||
/// underlying type if the type is an opaque.
|
|
||||||
///
|
|
||||||
/// Note that if this is an associated type, this is not the `DefId` of the
|
|
||||||
/// `TraitRef` containing this associated type, which is in `tcx.associated_item(def_id).container`,
|
|
||||||
/// aka. `tcx.parent(def_id)`.
|
|
||||||
pub def_id: DefId,
|
|
||||||
|
|
||||||
/// This field exists to prevent the creation of `AliasT` without using
|
|
||||||
/// [AliasTy::new].
|
|
||||||
_use_alias_ty_new_instead: (),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> AliasTy<'tcx> {
|
|
||||||
pub fn new(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
def_id: DefId,
|
|
||||||
args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
|
|
||||||
) -> ty::AliasTy<'tcx> {
|
|
||||||
let args = tcx.check_and_mk_args(def_id, args);
|
|
||||||
ty::AliasTy { def_id, args, _use_alias_ty_new_instead: () }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasTyKind {
|
|
||||||
match tcx.def_kind(self.def_id) {
|
|
||||||
DefKind::AssocTy
|
|
||||||
if let DefKind::Impl { of_trait: false } =
|
|
||||||
tcx.def_kind(tcx.parent(self.def_id)) =>
|
|
||||||
{
|
|
||||||
ty::Inherent
|
|
||||||
}
|
|
||||||
DefKind::AssocTy => ty::Projection,
|
|
||||||
DefKind::OpaqueTy => ty::Opaque,
|
|
||||||
DefKind::TyAlias => ty::Weak,
|
|
||||||
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Whether this alias type is an opaque.
|
|
||||||
pub fn is_opaque(self, tcx: TyCtxt<'tcx>) -> bool {
|
|
||||||
matches!(self.kind(tcx), ty::Opaque)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
|
|
||||||
Ty::new_alias(tcx, self.kind(tcx), self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The following methods work only with (trait) associated type projections.
|
|
||||||
impl<'tcx> AliasTy<'tcx> {
|
|
||||||
pub fn self_ty(self) -> Ty<'tcx> {
|
|
||||||
self.args.type_at(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
|
|
||||||
AliasTy::new(tcx, self.def_id, [self_ty.into()].into_iter().chain(self.args.iter().skip(1)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
|
|
||||||
match tcx.def_kind(self.def_id) {
|
|
||||||
DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id),
|
|
||||||
kind => bug!("expected a projection AliasTy; found {kind:?}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extracts the underlying trait reference and own args from this projection.
|
|
||||||
/// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
|
|
||||||
/// then this function would return a `T: StreamingIterator` trait reference and `['a]` as the own args
|
|
||||||
pub fn trait_ref_and_own_args(
|
|
||||||
self,
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
|
|
||||||
let trait_def_id = self.trait_def_id(tcx);
|
|
||||||
let trait_generics = tcx.generics_of(trait_def_id);
|
|
||||||
(
|
|
||||||
ty::TraitRef::new(tcx, trait_def_id, self.args.truncate_to(tcx, trait_generics)),
|
|
||||||
&self.args[trait_generics.count()..],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extracts the underlying trait reference from this projection.
|
|
||||||
/// For example, if this is a projection of `<T as Iterator>::Item`,
|
|
||||||
/// then this function would return a `T: Iterator` trait reference.
|
|
||||||
///
|
|
||||||
/// WARNING: This will drop the args for generic associated types
|
|
||||||
/// consider calling [Self::trait_ref_and_own_args] to get those
|
|
||||||
/// as well.
|
|
||||||
pub fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
|
|
||||||
let def_id = self.trait_def_id(tcx);
|
|
||||||
ty::TraitRef::new(tcx, def_id, self.args.truncate_to(tcx, tcx.generics_of(def_id)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The following methods work only with inherent associated type projections.
|
|
||||||
impl<'tcx> AliasTy<'tcx> {
|
|
||||||
/// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that.
|
|
||||||
///
|
|
||||||
/// Does the following transformation:
|
|
||||||
///
|
|
||||||
/// ```text
|
|
||||||
/// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m]
|
|
||||||
///
|
|
||||||
/// I_i impl args
|
|
||||||
/// P_j GAT args
|
|
||||||
/// ```
|
|
||||||
pub fn rebase_inherent_args_onto_impl(
|
|
||||||
self,
|
|
||||||
impl_args: ty::GenericArgsRef<'tcx>,
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
) -> ty::GenericArgsRef<'tcx> {
|
|
||||||
debug_assert_eq!(self.kind(tcx), ty::Inherent);
|
|
||||||
|
|
||||||
tcx.mk_args_from_iter(impl_args.into_iter().chain(self.args.into_iter().skip(1)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
|
#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
|
||||||
pub struct GenSig<'tcx> {
|
pub struct GenSig<'tcx> {
|
||||||
pub resume_ty: Ty<'tcx>,
|
pub resume_ty: Ty<'tcx>,
|
||||||
|
@ -2020,6 +1652,14 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
|
||||||
fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
|
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 })
|
Ty::new_bound(tcx, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_alias(
|
||||||
|
interner: TyCtxt<'tcx>,
|
||||||
|
kind: ty::AliasTyKind,
|
||||||
|
alias_ty: ty::AliasTy<'tcx>,
|
||||||
|
) -> Self {
|
||||||
|
Ty::new_alias(interner, kind, alias_ty)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type utilities
|
/// Type utilities
|
||||||
|
|
|
@ -1130,7 +1130,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for WeakAliasTypeExpander<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||||
if !ct.ty().has_type_flags(ty::TypeFlags::HAS_TY_WEAK) {
|
if !ct.has_type_flags(ty::TypeFlags::HAS_TY_WEAK) {
|
||||||
return ct;
|
return ct;
|
||||||
}
|
}
|
||||||
ct.super_fold_with(self)
|
ct.super_fold_with(self)
|
||||||
|
|
|
@ -61,17 +61,7 @@ fn coverage_ids_info<'tcx>(
|
||||||
.max()
|
.max()
|
||||||
.unwrap_or(CounterId::ZERO);
|
.unwrap_or(CounterId::ZERO);
|
||||||
|
|
||||||
let mcdc_bitmap_bytes = mir_body
|
CoverageIdsInfo { max_counter_id }
|
||||||
.coverage_branch_info
|
|
||||||
.as_deref()
|
|
||||||
.map(|info| {
|
|
||||||
info.mcdc_decision_spans
|
|
||||||
.iter()
|
|
||||||
.fold(0, |acc, decision| acc + (1_u32 << decision.conditions_num).div_ceil(8))
|
|
||||||
})
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
CoverageIdsInfo { max_counter_id, mcdc_bitmap_bytes }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_coverage_in_mir_body<'a, 'tcx>(
|
fn all_coverage_in_mir_body<'a, 'tcx>(
|
||||||
|
|
|
@ -686,20 +686,35 @@ impl<'a> Parser<'a> {
|
||||||
(None, self.parse_path(PathStyle::Expr)?)
|
(None, self.parse_path(PathStyle::Expr)?)
|
||||||
};
|
};
|
||||||
|
|
||||||
let rename = if self.eat_keyword(kw::As) { Some(self.parse_ident()?) } else { None };
|
let rename = |this: &mut Self| {
|
||||||
|
Ok(if this.eat_keyword(kw::As) { Some(this.parse_ident()?) } else { None })
|
||||||
let body = if self.check(&token::OpenDelim(Delimiter::Brace)) {
|
|
||||||
Some(self.parse_block()?)
|
|
||||||
} else {
|
|
||||||
self.expect(&token::Semi)?;
|
|
||||||
None
|
|
||||||
};
|
};
|
||||||
|
let body = |this: &mut Self| {
|
||||||
|
Ok(if this.check(&token::OpenDelim(Delimiter::Brace)) {
|
||||||
|
Some(this.parse_block()?)
|
||||||
|
} else {
|
||||||
|
this.expect(&token::Semi)?;
|
||||||
|
None
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
let (ident, item_kind) = if self.eat(&token::PathSep) {
|
||||||
|
let (suffixes, _) = self.parse_delim_comma_seq(Delimiter::Brace, |p| {
|
||||||
|
Ok((p.parse_path_segment_ident()?, rename(p)?))
|
||||||
|
})?;
|
||||||
|
let deleg = DelegationMac { qself, prefix: path, suffixes, body: body(self)? };
|
||||||
|
(Ident::empty(), ItemKind::DelegationMac(Box::new(deleg)))
|
||||||
|
} else {
|
||||||
|
let rename = rename(self)?;
|
||||||
|
let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident);
|
||||||
|
let deleg = Delegation { id: DUMMY_NODE_ID, qself, path, rename, body: body(self)? };
|
||||||
|
(ident, ItemKind::Delegation(Box::new(deleg)))
|
||||||
|
};
|
||||||
|
|
||||||
let span = span.to(self.prev_token.span);
|
let span = span.to(self.prev_token.span);
|
||||||
self.psess.gated_spans.gate(sym::fn_delegation, span);
|
self.psess.gated_spans.gate(sym::fn_delegation, span);
|
||||||
|
|
||||||
let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident);
|
Ok((ident, item_kind))
|
||||||
let deleg = Delegation { id: DUMMY_NODE_ID, qself, path, rename, body };
|
|
||||||
Ok((ident, ItemKind::Delegation(Box::new(deleg))))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_item_list<T>(
|
fn parse_item_list<T>(
|
||||||
|
|
|
@ -95,12 +95,15 @@ impl<'a> Parser<'a> {
|
||||||
debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count);
|
debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.recover_colon_before_qpath_proj() {
|
let is_import_coupler = self.is_import_coupler();
|
||||||
|
if !is_import_coupler && !self.recover_colon_before_qpath_proj() {
|
||||||
self.expect(&token::PathSep)?;
|
self.expect(&token::PathSep)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let qself = P(QSelf { ty, path_span, position: path.segments.len() });
|
let qself = P(QSelf { ty, path_span, position: path.segments.len() });
|
||||||
self.parse_path_segments(&mut path.segments, style, None)?;
|
if !is_import_coupler {
|
||||||
|
self.parse_path_segments(&mut path.segments, style, None)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
qself,
|
qself,
|
||||||
|
|
|
@ -522,7 +522,8 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
|
||||||
Impl,
|
Impl,
|
||||||
MacCall,
|
MacCall,
|
||||||
MacroDef,
|
MacroDef,
|
||||||
Delegation
|
Delegation,
|
||||||
|
DelegationMac
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
ast_visit::walk_item(self, i)
|
ast_visit::walk_item(self, i)
|
||||||
|
@ -650,7 +651,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
|
||||||
fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
|
fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
|
||||||
record_variants!(
|
record_variants!(
|
||||||
(self, i, i.kind, Id::None, ast, AssocItem, AssocItemKind),
|
(self, i, i.kind, Id::None, ast, AssocItem, AssocItemKind),
|
||||||
[Const, Fn, Type, MacCall, Delegation]
|
[Const, Fn, Type, MacCall, Delegation, DelegationMac]
|
||||||
);
|
);
|
||||||
ast_visit::walk_assoc_item(self, i, ctxt);
|
ast_visit::walk_assoc_item(self, i, ctxt);
|
||||||
}
|
}
|
||||||
|
|
|
@ -285,7 +285,9 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
|
||||||
ast::ItemKind::TraitAlias(_, _) => Target::TraitAlias,
|
ast::ItemKind::TraitAlias(_, _) => Target::TraitAlias,
|
||||||
ast::ItemKind::Impl(_) => Target::Impl,
|
ast::ItemKind::Impl(_) => Target::Impl,
|
||||||
ast::ItemKind::MacroDef(_) => Target::MacroDef,
|
ast::ItemKind::MacroDef(_) => Target::MacroDef,
|
||||||
ast::ItemKind::MacCall(_) => unreachable!("macros should have been expanded"),
|
ast::ItemKind::MacCall(_) | ast::ItemKind::DelegationMac(_) => {
|
||||||
|
unreachable!("macros should have been expanded")
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.check_for_lang(
|
self.check_for_lang(
|
||||||
|
@ -340,7 +342,9 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
|
||||||
}
|
}
|
||||||
ast::AssocItemKind::Const(ct) => (Target::AssocConst, Some(&ct.generics)),
|
ast::AssocItemKind::Const(ct) => (Target::AssocConst, Some(&ct.generics)),
|
||||||
ast::AssocItemKind::Type(ty) => (Target::AssocTy, Some(&ty.generics)),
|
ast::AssocItemKind::Type(ty) => (Target::AssocTy, Some(&ty.generics)),
|
||||||
ast::AssocItemKind::MacCall(_) => unreachable!("macros should have been expanded"),
|
ast::AssocItemKind::MacCall(_) | ast::AssocItemKind::DelegationMac(_) => {
|
||||||
|
unreachable!("macros should have been expanded")
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.check_for_lang(
|
self.check_for_lang(
|
||||||
|
|
|
@ -825,7 +825,9 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||||
}
|
}
|
||||||
ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {}
|
ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {}
|
||||||
|
|
||||||
ItemKind::MacroDef(..) | ItemKind::MacCall(_) => unreachable!(),
|
ItemKind::MacroDef(..) | ItemKind::MacCall(_) | ItemKind::DelegationMac(..) => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1381,7 +1383,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||||
| AssocItemKind::Delegation(..)
|
| AssocItemKind::Delegation(..)
|
||||||
| AssocItemKind::Fn(..) => ValueNS,
|
| AssocItemKind::Fn(..) => ValueNS,
|
||||||
AssocItemKind::Type(..) => TypeNS,
|
AssocItemKind::Type(..) => TypeNS,
|
||||||
AssocItemKind::MacCall(_) => bug!(), // handled above
|
AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => bug!(), // handled above
|
||||||
};
|
};
|
||||||
|
|
||||||
let parent = self.parent_scope.module;
|
let parent = self.parent_scope.module;
|
||||||
|
|
|
@ -139,6 +139,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
|
||||||
ItemKind::GlobalAsm(..) => DefKind::GlobalAsm,
|
ItemKind::GlobalAsm(..) => DefKind::GlobalAsm,
|
||||||
ItemKind::Use(..) => return visit::walk_item(self, i),
|
ItemKind::Use(..) => return visit::walk_item(self, i),
|
||||||
ItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),
|
ItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),
|
||||||
|
ItemKind::DelegationMac(..) => unreachable!(),
|
||||||
};
|
};
|
||||||
let def_id = self.create_def(i.id, i.ident.name, def_kind, i.span);
|
let def_id = self.create_def(i.id, i.ident.name, def_kind, i.span);
|
||||||
|
|
||||||
|
@ -278,6 +279,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
|
||||||
AssocItemKind::Const(..) => DefKind::AssocConst,
|
AssocItemKind::Const(..) => DefKind::AssocConst,
|
||||||
AssocItemKind::Type(..) => DefKind::AssocTy,
|
AssocItemKind::Type(..) => DefKind::AssocTy,
|
||||||
AssocItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),
|
AssocItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),
|
||||||
|
AssocItemKind::DelegationMac(..) => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let def = self.create_def(i.id, i.ident.name, def_kind, i.span);
|
let def = self.create_def(i.id, i.ident.name, def_kind, i.span);
|
||||||
|
|
|
@ -236,7 +236,7 @@ impl<'r, 'ast, 'tcx> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r, 't
|
||||||
ast::ItemKind::Impl(..) => return,
|
ast::ItemKind::Impl(..) => return,
|
||||||
|
|
||||||
// Should be unreachable at this stage
|
// Should be unreachable at this stage
|
||||||
ast::ItemKind::MacCall(..) => panic!(
|
ast::ItemKind::MacCall(..) | ast::ItemKind::DelegationMac(..) => panic!(
|
||||||
"ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
|
"ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
|
@ -2561,7 +2561,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||||
|
|
||||||
ItemKind::ExternCrate(..) => {}
|
ItemKind::ExternCrate(..) => {}
|
||||||
|
|
||||||
ItemKind::MacCall(_) => panic!("unexpanded macro in resolve!"),
|
ItemKind::MacCall(_) | ItemKind::DelegationMac(..) => {
|
||||||
|
panic!("unexpanded macro in resolve!")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2849,7 +2851,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||||
.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
|
.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
|
||||||
walk_assoc_item(this, generics, LifetimeBinderKind::Item, item)
|
walk_assoc_item(this, generics, LifetimeBinderKind::Item, item)
|
||||||
}),
|
}),
|
||||||
AssocItemKind::MacCall(_) => {
|
AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => {
|
||||||
panic!("unexpanded macro in resolve!")
|
panic!("unexpanded macro in resolve!")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -3116,7 +3118,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AssocItemKind::MacCall(_) => {
|
AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => {
|
||||||
panic!("unexpanded macro in resolve!")
|
panic!("unexpanded macro in resolve!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3218,7 +3220,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||||
AssocItemKind::Fn(..) => (E0324, "method"),
|
AssocItemKind::Fn(..) => (E0324, "method"),
|
||||||
AssocItemKind::Type(..) => (E0325, "type"),
|
AssocItemKind::Type(..) => (E0325, "type"),
|
||||||
AssocItemKind::Delegation(..) => (E0324, "method"),
|
AssocItemKind::Delegation(..) => (E0324, "method"),
|
||||||
AssocItemKind::MacCall(..) => span_bug!(span, "unexpanded macro"),
|
AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
|
||||||
|
span_bug!(span, "unexpanded macro")
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let trait_path = path_names_to_string(path);
|
let trait_path = path_names_to_string(path);
|
||||||
self.report_error(
|
self.report_error(
|
||||||
|
@ -4790,7 +4794,8 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
|
||||||
| ItemKind::ExternCrate(..)
|
| ItemKind::ExternCrate(..)
|
||||||
| ItemKind::MacroDef(..)
|
| ItemKind::MacroDef(..)
|
||||||
| ItemKind::GlobalAsm(..)
|
| ItemKind::GlobalAsm(..)
|
||||||
| ItemKind::MacCall(..) => {}
|
| ItemKind::MacCall(..)
|
||||||
|
| ItemKind::DelegationMac(..) => {}
|
||||||
ItemKind::Delegation(..) => {
|
ItemKind::Delegation(..) => {
|
||||||
// Delegated functions have lifetimes, their count is not necessarily zero.
|
// Delegated functions have lifetimes, their count is not necessarily zero.
|
||||||
// But skipping the delegation items here doesn't mean that the count will be considered zero,
|
// But skipping the delegation items here doesn't mean that the count will be considered zero,
|
||||||
|
|
|
@ -2045,7 +2045,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
AssocSuggestion::MethodWithSelf { called }
|
AssocSuggestion::MethodWithSelf { called }
|
||||||
}
|
}
|
||||||
ast::AssocItemKind::Delegation(..) => AssocSuggestion::AssocFn { called },
|
ast::AssocItemKind::Delegation(..) => AssocSuggestion::AssocFn { called },
|
||||||
ast::AssocItemKind::MacCall(_) => continue,
|
ast::AssocItemKind::MacCall(_) | ast::AssocItemKind::DelegationMac(..) => {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE};
|
||||||
use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES};
|
use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES};
|
||||||
use rustc_session::lint::BuiltinLintDiag;
|
use rustc_session::lint::BuiltinLintDiag;
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
|
use rustc_span::edit_distance::edit_distance;
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::hygiene::{self, ExpnData, ExpnKind, LocalExpnId};
|
use rustc_span::hygiene::{self, ExpnData, ExpnKind, LocalExpnId};
|
||||||
use rustc_span::hygiene::{AstPass, MacroKind};
|
use rustc_span::hygiene::{AstPass, MacroKind};
|
||||||
|
@ -568,15 +569,24 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if res == Res::NonMacroAttr(NonMacroAttrKind::Tool)
|
if res == Res::NonMacroAttr(NonMacroAttrKind::Tool)
|
||||||
&& path.segments.len() >= 2
|
&& let [namespace, attribute, ..] = &*path.segments
|
||||||
&& path.segments[0].ident.name == sym::diagnostic
|
&& namespace.ident.name == sym::diagnostic
|
||||||
&& path.segments[1].ident.name != sym::on_unimplemented
|
&& attribute.ident.name != sym::on_unimplemented
|
||||||
{
|
{
|
||||||
self.tcx.sess.psess.buffer_lint(
|
let distance =
|
||||||
|
edit_distance(attribute.ident.name.as_str(), sym::on_unimplemented.as_str(), 5);
|
||||||
|
|
||||||
|
let help = if distance.is_some() {
|
||||||
|
BuiltinLintDiag::MaybeTypo { span: attribute.span(), name: sym::on_unimplemented }
|
||||||
|
} else {
|
||||||
|
BuiltinLintDiag::Normal
|
||||||
|
};
|
||||||
|
self.tcx.sess.psess.buffer_lint_with_diagnostic(
|
||||||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||||
path.segments[1].span(),
|
attribute.span(),
|
||||||
node_id,
|
node_id,
|
||||||
"unknown diagnostic attribute",
|
"unknown diagnostic attribute",
|
||||||
|
help,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -779,16 +779,21 @@ impl RiscvInterruptKind {
|
||||||
/// Metadata describing how the arguments to a native function
|
/// Metadata describing how the arguments to a native function
|
||||||
/// should be passed in order to respect the native ABI.
|
/// should be passed in order to respect the native ABI.
|
||||||
///
|
///
|
||||||
|
/// The signature represented by this type may not match the MIR function signature.
|
||||||
|
/// Certain attributes, like `#[track_caller]` can introduce additional arguments, which are present in [`FnAbi`], but not in `FnSig`.
|
||||||
|
/// While this difference is rarely relevant, it should still be kept in mind.
|
||||||
|
///
|
||||||
/// I will do my best to describe this structure, but these
|
/// I will do my best to describe this structure, but these
|
||||||
/// comments are reverse-engineered and may be inaccurate. -NDM
|
/// comments are reverse-engineered and may be inaccurate. -NDM
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic)]
|
#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic)]
|
||||||
pub struct FnAbi<'a, Ty> {
|
pub struct FnAbi<'a, Ty> {
|
||||||
/// The LLVM types of each argument.
|
/// The type, layout, and information about how each argument is passed.
|
||||||
pub args: Box<[ArgAbi<'a, Ty>]>,
|
pub args: Box<[ArgAbi<'a, Ty>]>,
|
||||||
|
|
||||||
/// LLVM return type.
|
/// The layout, type, and the way a value is returned from this function.
|
||||||
pub ret: ArgAbi<'a, Ty>,
|
pub ret: ArgAbi<'a, Ty>,
|
||||||
|
|
||||||
|
/// Marks this function as variadic (accepting a variable number of arguments).
|
||||||
pub c_variadic: bool,
|
pub c_variadic: bool,
|
||||||
|
|
||||||
/// The count of non-variadic arguments.
|
/// The count of non-variadic arguments.
|
||||||
|
@ -796,9 +801,9 @@ pub struct FnAbi<'a, Ty> {
|
||||||
/// Should only be different from args.len() when c_variadic is true.
|
/// Should only be different from args.len() when c_variadic is true.
|
||||||
/// This can be used to know whether an argument is variadic or not.
|
/// This can be used to know whether an argument is variadic or not.
|
||||||
pub fixed_count: u32,
|
pub fixed_count: u32,
|
||||||
|
/// The calling convention of this function.
|
||||||
pub conv: Conv,
|
pub conv: Conv,
|
||||||
|
/// Indicates if an unwind may happen across a call to this function.
|
||||||
pub can_unwind: bool,
|
pub can_unwind: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! Code shared by trait and projection goals for candidate assembly.
|
//! Code shared by trait and projection goals for candidate assembly.
|
||||||
|
|
||||||
use crate::solve::GoalSource;
|
use crate::solve::GoalSource;
|
||||||
use crate::solve::{inspect, EvalCtxt, SolverMode};
|
use crate::solve::{EvalCtxt, SolverMode};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_infer::traits::query::NoSolution;
|
use rustc_infer::traits::query::NoSolution;
|
||||||
use rustc_middle::bug;
|
use rustc_middle::bug;
|
||||||
|
@ -16,7 +16,6 @@ use rustc_middle::ty::{fast_reject, TypeFoldable};
|
||||||
use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
|
use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
|
||||||
use rustc_span::{ErrorGuaranteed, DUMMY_SP};
|
use rustc_span::{ErrorGuaranteed, DUMMY_SP};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::mem;
|
|
||||||
|
|
||||||
pub(super) mod structural_traits;
|
pub(super) mod structural_traits;
|
||||||
|
|
||||||
|
@ -792,17 +791,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
goal: Goal<'tcx, G>,
|
goal: Goal<'tcx, G>,
|
||||||
candidates: &mut Vec<Candidate<'tcx>>,
|
candidates: &mut Vec<Candidate<'tcx>>,
|
||||||
) {
|
) {
|
||||||
// HACK: We temporarily remove the `ProofTreeBuilder` to
|
|
||||||
// avoid adding `Trait` candidates to the candidates used
|
|
||||||
// to prove the current goal.
|
|
||||||
let inspect = mem::replace(&mut self.inspect, inspect::ProofTreeBuilder::new_noop());
|
|
||||||
|
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> =
|
let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> =
|
||||||
goal.with(tcx, goal.predicate.trait_ref(tcx));
|
goal.with(tcx, goal.predicate.trait_ref(tcx));
|
||||||
let mut trait_candidates_from_env = Vec::new();
|
|
||||||
self.assemble_param_env_candidates(trait_goal, &mut trait_candidates_from_env);
|
let mut trait_candidates_from_env = vec![];
|
||||||
self.assemble_alias_bound_candidates(trait_goal, &mut trait_candidates_from_env);
|
self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| {
|
||||||
|
ecx.assemble_param_env_candidates(trait_goal, &mut trait_candidates_from_env);
|
||||||
|
ecx.assemble_alias_bound_candidates(trait_goal, &mut trait_candidates_from_env);
|
||||||
|
});
|
||||||
|
|
||||||
if !trait_candidates_from_env.is_empty() {
|
if !trait_candidates_from_env.is_empty() {
|
||||||
let trait_env_result = self.merge_candidates(trait_candidates_from_env);
|
let trait_env_result = self.merge_candidates(trait_candidates_from_env);
|
||||||
match trait_env_result.unwrap().value.certainty {
|
match trait_env_result.unwrap().value.certainty {
|
||||||
|
@ -831,7 +829,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.inspect = inspect;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If there are multiple ways to prove a trait or projection goal, we have
|
/// If there are multiple ways to prove a trait or projection goal, we have
|
||||||
|
|
|
@ -176,7 +176,8 @@ fn to_selection<'tcx>(
|
||||||
| ProbeKind::UnsizeAssembly
|
| ProbeKind::UnsizeAssembly
|
||||||
| ProbeKind::UpcastProjectionCompatibility
|
| ProbeKind::UpcastProjectionCompatibility
|
||||||
| ProbeKind::OpaqueTypeStorageLookup { result: _ }
|
| ProbeKind::OpaqueTypeStorageLookup { result: _ }
|
||||||
| ProbeKind::Root { result: _ } => {
|
| ProbeKind::Root { result: _ }
|
||||||
|
| ProbeKind::ShadowedEnvProbing => {
|
||||||
span_bug!(span, "didn't expect to assemble trait candidate from {:#?}", cand.kind())
|
span_bug!(span, "didn't expect to assemble trait candidate from {:#?}", cand.kind())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -18,8 +18,8 @@ use rustc_middle::traits::query::NoSolution;
|
||||||
use rustc_middle::traits::solve::{inspect, QueryResult};
|
use rustc_middle::traits::solve::{inspect, QueryResult};
|
||||||
use rustc_middle::traits::solve::{Certainty, Goal};
|
use rustc_middle::traits::solve::{Certainty, Goal};
|
||||||
use rustc_middle::traits::ObligationCause;
|
use rustc_middle::traits::ObligationCause;
|
||||||
use rustc_middle::ty;
|
|
||||||
use rustc_middle::ty::TypeFoldable;
|
use rustc_middle::ty::TypeFoldable;
|
||||||
|
use rustc_middle::{bug, ty};
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
|
|
||||||
use crate::solve::eval_ctxt::canonical;
|
use crate::solve::eval_ctxt::canonical;
|
||||||
|
@ -290,12 +290,25 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
|
||||||
match *step {
|
match *step {
|
||||||
inspect::ProbeStep::AddGoal(source, goal) => nested_goals.push((source, goal)),
|
inspect::ProbeStep::AddGoal(source, goal) => nested_goals.push((source, goal)),
|
||||||
inspect::ProbeStep::NestedProbe(ref probe) => {
|
inspect::ProbeStep::NestedProbe(ref probe) => {
|
||||||
// Nested probes have to prove goals added in their parent
|
match probe.kind {
|
||||||
// but do not leak them, so we truncate the added goals
|
// These never assemble candidates for the goal we're trying to solve.
|
||||||
// afterwards.
|
inspect::ProbeKind::UpcastProjectionCompatibility
|
||||||
let num_goals = nested_goals.len();
|
| inspect::ProbeKind::ShadowedEnvProbing => continue,
|
||||||
self.candidates_recur(candidates, nested_goals, probe);
|
|
||||||
nested_goals.truncate(num_goals);
|
inspect::ProbeKind::NormalizedSelfTyAssembly
|
||||||
|
| inspect::ProbeKind::UnsizeAssembly
|
||||||
|
| inspect::ProbeKind::Root { .. }
|
||||||
|
| inspect::ProbeKind::TryNormalizeNonRigid { .. }
|
||||||
|
| inspect::ProbeKind::TraitCandidate { .. }
|
||||||
|
| inspect::ProbeKind::OpaqueTypeStorageLookup { .. } => {
|
||||||
|
// Nested probes have to prove goals added in their parent
|
||||||
|
// but do not leak them, so we truncate the added goals
|
||||||
|
// afterwards.
|
||||||
|
let num_goals = nested_goals.len();
|
||||||
|
self.candidates_recur(candidates, nested_goals, probe);
|
||||||
|
nested_goals.truncate(num_goals);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => {
|
inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => {
|
||||||
assert_eq!(shallow_certainty.replace(c), None);
|
assert_eq!(shallow_certainty.replace(c), None);
|
||||||
|
@ -308,9 +321,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
match probe.kind {
|
match probe.kind {
|
||||||
inspect::ProbeKind::NormalizedSelfTyAssembly
|
inspect::ProbeKind::UpcastProjectionCompatibility
|
||||||
| inspect::ProbeKind::UnsizeAssembly
|
| inspect::ProbeKind::ShadowedEnvProbing => bug!(),
|
||||||
| inspect::ProbeKind::UpcastProjectionCompatibility => (),
|
|
||||||
|
inspect::ProbeKind::NormalizedSelfTyAssembly | inspect::ProbeKind::UnsizeAssembly => {}
|
||||||
|
|
||||||
// We add a candidate even for the root evaluation if there
|
// We add a candidate even for the root evaluation if there
|
||||||
// is only one way to prove a given goal, e.g. for `WellFormed`.
|
// is only one way to prove a given goal, e.g. for `WellFormed`.
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
|
use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
|
||||||
|
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
|
use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
|
||||||
|
@ -86,6 +87,46 @@ impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An unevaluated (potentially generic) constant used in the type-system.
|
||||||
|
#[derive(derivative::Derivative)]
|
||||||
|
#[derivative(
|
||||||
|
Clone(bound = ""),
|
||||||
|
Copy(bound = ""),
|
||||||
|
Hash(bound = ""),
|
||||||
|
PartialEq(bound = ""),
|
||||||
|
Eq(bound = "")
|
||||||
|
)]
|
||||||
|
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
|
||||||
|
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
|
||||||
|
pub struct UnevaluatedConst<I: Interner> {
|
||||||
|
pub def: I::DefId,
|
||||||
|
pub args: I::GenericArgs,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> UnevaluatedConst<I> {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(def: I::DefId, args: I::GenericArgs) -> UnevaluatedConst<I> {
|
||||||
|
UnevaluatedConst { def, args }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> fmt::Debug for UnevaluatedConst<I> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
WithInfcx::with_no_infcx(self).fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<I: Interner> DebugWithInfcx<I> for UnevaluatedConst<I> {
|
||||||
|
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
|
||||||
|
this: WithInfcx<'_, Infcx, &Self>,
|
||||||
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> core::fmt::Result {
|
||||||
|
f.debug_struct("UnevaluatedConst")
|
||||||
|
.field("def", &this.data.def)
|
||||||
|
.field("args", &this.wrap(this.data.args))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rustc_index::newtype_index! {
|
rustc_index::newtype_index! {
|
||||||
/// A **`const`** **v**ariable **ID**.
|
/// A **`const`** **v**ariable **ID**.
|
||||||
#[encodable]
|
#[encodable]
|
||||||
|
|
|
@ -5,7 +5,8 @@ use std::ops::Deref;
|
||||||
use crate::fold::TypeSuperFoldable;
|
use crate::fold::TypeSuperFoldable;
|
||||||
use crate::visit::{Flags, TypeSuperVisitable};
|
use crate::visit::{Flags, TypeSuperVisitable};
|
||||||
use crate::{
|
use crate::{
|
||||||
BoundVar, ConstKind, DebruijnIndex, DebugWithInfcx, Interner, RegionKind, TyKind, UniverseIndex,
|
AliasTy, AliasTyKind, BoundVar, ConstKind, DebruijnIndex, DebugWithInfcx, Interner, RegionKind,
|
||||||
|
TyKind, UnevaluatedConst, UniverseIndex,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait Ty<I: Interner<Ty = Self>>:
|
pub trait Ty<I: Interner<Ty = Self>>:
|
||||||
|
@ -14,12 +15,15 @@ pub trait Ty<I: Interner<Ty = Self>>:
|
||||||
+ Hash
|
+ Hash
|
||||||
+ Eq
|
+ Eq
|
||||||
+ Into<I::GenericArg>
|
+ Into<I::GenericArg>
|
||||||
|
+ Into<I::Term>
|
||||||
+ IntoKind<Kind = TyKind<I>>
|
+ IntoKind<Kind = TyKind<I>>
|
||||||
+ TypeSuperVisitable<I>
|
+ TypeSuperVisitable<I>
|
||||||
+ TypeSuperFoldable<I>
|
+ TypeSuperFoldable<I>
|
||||||
+ Flags
|
+ Flags
|
||||||
{
|
{
|
||||||
fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self;
|
fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self;
|
||||||
|
|
||||||
|
fn new_alias(interner: I, kind: AliasTyKind, alias_ty: AliasTy<I>) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Region<I: Interner<Region = Self>>:
|
pub trait Region<I: Interner<Region = Self>>:
|
||||||
|
@ -36,6 +40,7 @@ pub trait Const<I: Interner<Const = Self>>:
|
||||||
+ Hash
|
+ Hash
|
||||||
+ Eq
|
+ Eq
|
||||||
+ Into<I::GenericArg>
|
+ Into<I::GenericArg>
|
||||||
|
+ Into<I::Term>
|
||||||
+ IntoKind<Kind = ConstKind<I>>
|
+ IntoKind<Kind = ConstKind<I>>
|
||||||
+ TypeSuperVisitable<I>
|
+ TypeSuperVisitable<I>
|
||||||
+ TypeSuperFoldable<I>
|
+ TypeSuperFoldable<I>
|
||||||
|
@ -43,6 +48,8 @@ pub trait Const<I: Interner<Const = Self>>:
|
||||||
{
|
{
|
||||||
fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar, ty: I::Ty) -> Self;
|
fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar, ty: I::Ty) -> Self;
|
||||||
|
|
||||||
|
fn new_unevaluated(interner: I, uv: UnevaluatedConst<I>, ty: I::Ty) -> Self;
|
||||||
|
|
||||||
fn ty(self) -> I::Ty;
|
fn ty(self) -> I::Ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,21 +96,3 @@ pub trait BoundVars<I: Interner> {
|
||||||
|
|
||||||
fn has_no_bound_vars(&self) -> bool;
|
fn has_no_bound_vars(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait AliasTerm<I: Interner>: Copy + DebugWithInfcx<I> + Hash + Eq + Sized {
|
|
||||||
fn new(
|
|
||||||
interner: I,
|
|
||||||
trait_def_id: I::DefId,
|
|
||||||
args: impl IntoIterator<Item: Into<I::GenericArg>>,
|
|
||||||
) -> Self;
|
|
||||||
|
|
||||||
fn def_id(self) -> I::DefId;
|
|
||||||
|
|
||||||
fn args(self) -> I::GenericArgs;
|
|
||||||
|
|
||||||
fn trait_def_id(self, interner: I) -> I::DefId;
|
|
||||||
|
|
||||||
fn self_ty(self) -> I::Ty;
|
|
||||||
|
|
||||||
fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self;
|
|
||||||
}
|
|
||||||
|
|
|
@ -6,13 +6,16 @@ use crate::inherent::*;
|
||||||
use crate::ir_print::IrPrint;
|
use crate::ir_print::IrPrint;
|
||||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
||||||
use crate::{
|
use crate::{
|
||||||
CanonicalVarInfo, CoercePredicate, DebugWithInfcx, ExistentialProjection, ExistentialTraitRef,
|
AliasTerm, AliasTermKind, AliasTy, AliasTyKind, CanonicalVarInfo, CoercePredicate,
|
||||||
NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef,
|
DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, NormalizesTo, ProjectionPredicate,
|
||||||
|
SubtypePredicate, TraitPredicate, TraitRef,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait Interner:
|
pub trait Interner:
|
||||||
Sized
|
Sized
|
||||||
+ Copy
|
+ Copy
|
||||||
|
+ IrPrint<AliasTy<Self>>
|
||||||
|
+ IrPrint<AliasTerm<Self>>
|
||||||
+ IrPrint<TraitRef<Self>>
|
+ IrPrint<TraitRef<Self>>
|
||||||
+ IrPrint<TraitPredicate<Self>>
|
+ IrPrint<TraitPredicate<Self>>
|
||||||
+ IrPrint<ExistentialTraitRef<Self>>
|
+ IrPrint<ExistentialTraitRef<Self>>
|
||||||
|
@ -27,6 +30,7 @@ pub trait Interner:
|
||||||
type AdtDef: Copy + Debug + Hash + Eq;
|
type AdtDef: Copy + Debug + Hash + Eq;
|
||||||
|
|
||||||
type GenericArgs: GenericArgs<Self>;
|
type GenericArgs: GenericArgs<Self>;
|
||||||
|
type GenericArgsSlice: Copy + Debug + Hash + Eq;
|
||||||
type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Eq;
|
type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Eq;
|
||||||
type Term: Copy + Debug + Hash + Eq;
|
type Term: Copy + Debug + Hash + Eq;
|
||||||
|
|
||||||
|
@ -39,7 +43,6 @@ pub trait Interner:
|
||||||
// Kinds of tys
|
// Kinds of tys
|
||||||
type Ty: Ty<Self>;
|
type Ty: Ty<Self>;
|
||||||
type Tys: Copy + Debug + Hash + Eq + IntoIterator<Item = Self::Ty>;
|
type Tys: Copy + Debug + Hash + Eq + IntoIterator<Item = Self::Ty>;
|
||||||
type AliasTy: Copy + DebugWithInfcx<Self> + Hash + Eq + Sized;
|
|
||||||
type ParamTy: Copy + Debug + Hash + Eq;
|
type ParamTy: Copy + Debug + Hash + Eq;
|
||||||
type BoundTy: Copy + Debug + Hash + Eq;
|
type BoundTy: Copy + Debug + Hash + Eq;
|
||||||
type PlaceholderTy: PlaceholderLike;
|
type PlaceholderTy: PlaceholderLike;
|
||||||
|
@ -74,7 +77,6 @@ pub trait Interner:
|
||||||
type RegionOutlivesPredicate: Copy + Debug + Hash + Eq;
|
type RegionOutlivesPredicate: Copy + Debug + Hash + Eq;
|
||||||
type TypeOutlivesPredicate: Copy + Debug + Hash + Eq;
|
type TypeOutlivesPredicate: Copy + Debug + Hash + Eq;
|
||||||
type ProjectionPredicate: Copy + Debug + Hash + Eq;
|
type ProjectionPredicate: Copy + Debug + Hash + Eq;
|
||||||
type AliasTerm: AliasTerm<Self>;
|
|
||||||
type NormalizesTo: Copy + Debug + Hash + Eq;
|
type NormalizesTo: Copy + Debug + Hash + Eq;
|
||||||
type SubtypePredicate: Copy + Debug + Hash + Eq;
|
type SubtypePredicate: Copy + Debug + Hash + Eq;
|
||||||
type CoercePredicate: Copy + Debug + Hash + Eq;
|
type CoercePredicate: Copy + Debug + Hash + Eq;
|
||||||
|
@ -86,8 +88,23 @@ pub trait Interner:
|
||||||
type GenericsOf: GenericsOf<Self>;
|
type GenericsOf: GenericsOf<Self>;
|
||||||
fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf;
|
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 alias_ty_kind(self, alias: AliasTy<Self>) -> AliasTyKind;
|
||||||
|
|
||||||
|
fn alias_term_kind(self, alias: AliasTerm<Self>) -> AliasTermKind;
|
||||||
|
|
||||||
|
fn trait_ref_and_own_args_for_alias(
|
||||||
|
self,
|
||||||
|
def_id: Self::DefId,
|
||||||
|
args: Self::GenericArgs,
|
||||||
|
) -> (TraitRef<Self>, Self::GenericArgsSlice);
|
||||||
|
|
||||||
fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs;
|
fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs;
|
||||||
|
|
||||||
|
fn mk_args_from_iter(self, args: impl Iterator<Item = Self::GenericArg>) -> Self::GenericArgs;
|
||||||
|
|
||||||
fn check_and_mk_args(
|
fn check_and_mk_args(
|
||||||
self,
|
self,
|
||||||
def_id: Self::DefId,
|
def_id: Self::DefId,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
CoercePredicate, ExistentialProjection, ExistentialTraitRef, Interner, NormalizesTo,
|
AliasTerm, AliasTy, CoercePredicate, ExistentialProjection, ExistentialTraitRef, Interner,
|
||||||
ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef,
|
NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait IrPrint<T> {
|
pub trait IrPrint<T> {
|
||||||
|
@ -43,6 +43,8 @@ define_display_via_print!(
|
||||||
NormalizesTo,
|
NormalizesTo,
|
||||||
SubtypePredicate,
|
SubtypePredicate,
|
||||||
CoercePredicate,
|
CoercePredicate,
|
||||||
|
AliasTy,
|
||||||
|
AliasTerm,
|
||||||
);
|
);
|
||||||
|
|
||||||
define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection);
|
define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection);
|
||||||
|
|
|
@ -6,7 +6,9 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen
|
||||||
|
|
||||||
use crate::inherent::*;
|
use crate::inherent::*;
|
||||||
use crate::visit::TypeVisitableExt as _;
|
use crate::visit::TypeVisitableExt as _;
|
||||||
use crate::{DebugWithInfcx, Interner};
|
use crate::{
|
||||||
|
AliasTy, AliasTyKind, DebugWithInfcx, InferCtxtLike, Interner, UnevaluatedConst, WithInfcx,
|
||||||
|
};
|
||||||
|
|
||||||
/// A complete reference to a trait. These take numerous guises in syntax,
|
/// A complete reference to a trait. These take numerous guises in syntax,
|
||||||
/// but perhaps the most recognizable form is in a where-clause:
|
/// but perhaps the most recognizable form is in a where-clause:
|
||||||
|
@ -272,20 +274,20 @@ impl<I: Interner> ExistentialProjection<I> {
|
||||||
/// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
|
/// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
|
||||||
/// then this function would return an `exists T. T: Iterator` existential trait
|
/// then this function would return an `exists T. T: Iterator` existential trait
|
||||||
/// reference.
|
/// reference.
|
||||||
pub fn trait_ref(&self, tcx: I) -> ExistentialTraitRef<I> {
|
pub fn trait_ref(&self, interner: I) -> ExistentialTraitRef<I> {
|
||||||
let def_id = tcx.parent(self.def_id);
|
let def_id = interner.parent(self.def_id);
|
||||||
let args_count = tcx.generics_of(def_id).count() - 1;
|
let args_count = interner.generics_of(def_id).count() - 1;
|
||||||
let args = tcx.mk_args(&self.args[..args_count]);
|
let args = interner.mk_args(&self.args[..args_count]);
|
||||||
ExistentialTraitRef { def_id, args }
|
ExistentialTraitRef { def_id, args }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> ProjectionPredicate<I> {
|
pub fn with_self_ty(&self, interner: I, self_ty: I::Ty) -> ProjectionPredicate<I> {
|
||||||
// otherwise the escaping regions would be captured by the binders
|
// otherwise the escaping regions would be captured by the binders
|
||||||
debug_assert!(!self_ty.has_escaping_bound_vars());
|
debug_assert!(!self_ty.has_escaping_bound_vars());
|
||||||
|
|
||||||
ProjectionPredicate {
|
ProjectionPredicate {
|
||||||
projection_term: I::AliasTerm::new(
|
projection_term: AliasTerm::new(
|
||||||
tcx,
|
interner,
|
||||||
self.def_id,
|
self.def_id,
|
||||||
[self_ty.into()].into_iter().chain(self.args),
|
[self_ty.into()].into_iter().chain(self.args),
|
||||||
),
|
),
|
||||||
|
@ -293,13 +295,13 @@ impl<I: Interner> ExistentialProjection<I> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn erase_self_ty(tcx: I, projection_predicate: ProjectionPredicate<I>) -> Self {
|
pub fn erase_self_ty(interner: I, projection_predicate: ProjectionPredicate<I>) -> Self {
|
||||||
// Assert there is a Self.
|
// Assert there is a Self.
|
||||||
projection_predicate.projection_term.args().type_at(0);
|
projection_predicate.projection_term.args.type_at(0);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
def_id: projection_predicate.projection_term.def_id(),
|
def_id: projection_predicate.projection_term.def_id,
|
||||||
args: tcx.mk_args(&projection_predicate.projection_term.args()[1..]),
|
args: interner.mk_args(&projection_predicate.projection_term.args[1..]),
|
||||||
term: projection_predicate.term,
|
term: projection_predicate.term,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -339,6 +341,190 @@ impl AliasTermKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the unprojected term of a projection goal.
|
||||||
|
///
|
||||||
|
/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
|
||||||
|
/// * For an inherent projection, this would be `Ty::N<...>`.
|
||||||
|
/// * For an opaque type, there is no explicit syntax.
|
||||||
|
#[derive(derivative::Derivative)]
|
||||||
|
#[derivative(
|
||||||
|
Clone(bound = ""),
|
||||||
|
Copy(bound = ""),
|
||||||
|
Hash(bound = ""),
|
||||||
|
PartialEq(bound = ""),
|
||||||
|
Eq(bound = "")
|
||||||
|
)]
|
||||||
|
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
|
||||||
|
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
|
||||||
|
pub struct AliasTerm<I: Interner> {
|
||||||
|
/// The parameters of the associated or opaque item.
|
||||||
|
///
|
||||||
|
/// For a projection, these are the generic parameters for the trait and the
|
||||||
|
/// GAT parameters, if there are any.
|
||||||
|
///
|
||||||
|
/// For an inherent projection, they consist of the self type and the GAT parameters,
|
||||||
|
/// if there are any.
|
||||||
|
///
|
||||||
|
/// For RPIT the generic parameters are for the generics of the function,
|
||||||
|
/// while for TAIT it is used for the generic parameters of the alias.
|
||||||
|
pub args: I::GenericArgs,
|
||||||
|
|
||||||
|
/// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether
|
||||||
|
/// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if
|
||||||
|
/// this is an opaque.
|
||||||
|
///
|
||||||
|
/// During codegen, `interner.type_of(def_id)` can be used to get the type of the
|
||||||
|
/// underlying type if the type is an opaque.
|
||||||
|
///
|
||||||
|
/// Note that if this is an associated type, this is not the `DefId` of the
|
||||||
|
/// `TraitRef` containing this associated type, which is in `interner.associated_item(def_id).container`,
|
||||||
|
/// aka. `interner.parent(def_id)`.
|
||||||
|
pub def_id: I::DefId,
|
||||||
|
|
||||||
|
/// This field exists to prevent the creation of `AliasTerm` without using
|
||||||
|
/// [AliasTerm::new].
|
||||||
|
_use_alias_term_new_instead: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> std::fmt::Debug for AliasTerm<I> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
WithInfcx::with_no_infcx(self).fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<I: Interner> DebugWithInfcx<I> for AliasTerm<I> {
|
||||||
|
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
|
||||||
|
this: WithInfcx<'_, Infcx, &Self>,
|
||||||
|
f: &mut std::fmt::Formatter<'_>,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
f.debug_struct("AliasTerm")
|
||||||
|
.field("args", &this.map(|data| data.args))
|
||||||
|
.field("def_id", &this.data.def_id)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> AliasTerm<I> {
|
||||||
|
pub fn new(
|
||||||
|
interner: I,
|
||||||
|
def_id: I::DefId,
|
||||||
|
args: impl IntoIterator<Item: Into<I::GenericArg>>,
|
||||||
|
) -> AliasTerm<I> {
|
||||||
|
let args = interner.check_and_mk_args(def_id, args);
|
||||||
|
AliasTerm { def_id, args, _use_alias_term_new_instead: () }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expect_ty(self, interner: I) -> AliasTy<I> {
|
||||||
|
match self.kind(interner) {
|
||||||
|
AliasTermKind::ProjectionTy
|
||||||
|
| AliasTermKind::InherentTy
|
||||||
|
| AliasTermKind::OpaqueTy
|
||||||
|
| AliasTermKind::WeakTy => {}
|
||||||
|
AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => {
|
||||||
|
panic!("Cannot turn `UnevaluatedConst` into `AliasTy`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kind(self, interner: I) -> AliasTermKind {
|
||||||
|
interner.alias_term_kind(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_term(self, interner: I) -> I::Term {
|
||||||
|
match self.kind(interner) {
|
||||||
|
AliasTermKind::ProjectionTy => Ty::new_alias(
|
||||||
|
interner,
|
||||||
|
AliasTyKind::Projection,
|
||||||
|
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
AliasTermKind::InherentTy => Ty::new_alias(
|
||||||
|
interner,
|
||||||
|
AliasTyKind::Inherent,
|
||||||
|
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
AliasTermKind::OpaqueTy => Ty::new_alias(
|
||||||
|
interner,
|
||||||
|
AliasTyKind::Opaque,
|
||||||
|
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
AliasTermKind::WeakTy => Ty::new_alias(
|
||||||
|
interner,
|
||||||
|
AliasTyKind::Weak,
|
||||||
|
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => {
|
||||||
|
I::Const::new_unevaluated(
|
||||||
|
interner,
|
||||||
|
UnevaluatedConst::new(self.def_id, self.args),
|
||||||
|
interner.type_of_instantiated(self.def_id, self.args),
|
||||||
|
)
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The following methods work only with (trait) associated type projections.
|
||||||
|
impl<I: Interner> AliasTerm<I> {
|
||||||
|
pub fn self_ty(self) -> I::Ty {
|
||||||
|
self.args.type_at(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self {
|
||||||
|
AliasTerm::new(
|
||||||
|
interner,
|
||||||
|
self.def_id,
|
||||||
|
[self_ty.into()].into_iter().chain(self.args.into_iter().skip(1)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn trait_def_id(self, interner: I) -> I::DefId {
|
||||||
|
assert!(
|
||||||
|
matches!(
|
||||||
|
self.kind(interner),
|
||||||
|
AliasTermKind::ProjectionTy | AliasTermKind::ProjectionConst
|
||||||
|
),
|
||||||
|
"expected a projection"
|
||||||
|
);
|
||||||
|
interner.parent(self.def_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts the underlying trait reference and own args from this projection.
|
||||||
|
/// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
|
||||||
|
/// then this function would return a `T: StreamingIterator` trait reference and
|
||||||
|
/// `['a]` as the own args.
|
||||||
|
pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef<I>, I::GenericArgsSlice) {
|
||||||
|
interner.trait_ref_and_own_args_for_alias(self.def_id, self.args)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts the underlying trait reference from this projection.
|
||||||
|
/// For example, if this is a projection of `<T as Iterator>::Item`,
|
||||||
|
/// then this function would return a `T: Iterator` trait reference.
|
||||||
|
///
|
||||||
|
/// WARNING: This will drop the args for generic associated types
|
||||||
|
/// consider calling [Self::trait_ref_and_own_args] to get those
|
||||||
|
/// as well.
|
||||||
|
pub fn trait_ref(self, interner: I) -> TraitRef<I> {
|
||||||
|
self.trait_ref_and_own_args(interner).0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> From<AliasTy<I>> for AliasTerm<I> {
|
||||||
|
fn from(ty: AliasTy<I>) -> Self {
|
||||||
|
AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> From<UnevaluatedConst<I>> for AliasTerm<I> {
|
||||||
|
fn from(ct: UnevaluatedConst<I>) -> Self {
|
||||||
|
AliasTerm { args: ct.args, def_id: ct.def, _use_alias_term_new_instead: () }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This kind of predicate has no *direct* correspondent in the
|
/// This kind of predicate has no *direct* correspondent in the
|
||||||
/// syntax, but it roughly corresponds to the syntactic forms:
|
/// syntax, but it roughly corresponds to the syntactic forms:
|
||||||
///
|
///
|
||||||
|
@ -362,7 +548,7 @@ impl AliasTermKind {
|
||||||
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
|
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
|
||||||
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
|
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
|
||||||
pub struct ProjectionPredicate<I: Interner> {
|
pub struct ProjectionPredicate<I: Interner> {
|
||||||
pub projection_term: I::AliasTerm,
|
pub projection_term: AliasTerm<I>,
|
||||||
pub term: I::Term,
|
pub term: I::Term,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,16 +557,16 @@ impl<I: Interner> ProjectionPredicate<I> {
|
||||||
self.projection_term.self_ty()
|
self.projection_term.self_ty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> ProjectionPredicate<I> {
|
pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> ProjectionPredicate<I> {
|
||||||
Self { projection_term: self.projection_term.with_self_ty(tcx, self_ty), ..self }
|
Self { projection_term: self.projection_term.with_self_ty(interner, self_ty), ..self }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trait_def_id(self, tcx: I) -> I::DefId {
|
pub fn trait_def_id(self, interner: I) -> I::DefId {
|
||||||
self.projection_term.trait_def_id(tcx)
|
self.projection_term.trait_def_id(interner)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn def_id(self) -> I::DefId {
|
pub fn def_id(self) -> I::DefId {
|
||||||
self.projection_term.def_id()
|
self.projection_term.def_id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,7 +589,7 @@ impl<I: Interner> fmt::Debug for ProjectionPredicate<I> {
|
||||||
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
|
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
|
||||||
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
|
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
|
||||||
pub struct NormalizesTo<I: Interner> {
|
pub struct NormalizesTo<I: Interner> {
|
||||||
pub alias: I::AliasTerm,
|
pub alias: AliasTerm<I>,
|
||||||
pub term: I::Term,
|
pub term: I::Term,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,16 +598,16 @@ impl<I: Interner> NormalizesTo<I> {
|
||||||
self.alias.self_ty()
|
self.alias.self_ty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> NormalizesTo<I> {
|
pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> NormalizesTo<I> {
|
||||||
Self { alias: self.alias.with_self_ty(tcx, self_ty), ..self }
|
Self { alias: self.alias.with_self_ty(interner, self_ty), ..self }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trait_def_id(self, tcx: I) -> I::DefId {
|
pub fn trait_def_id(self, interner: I) -> I::DefId {
|
||||||
self.alias.trait_def_id(tcx)
|
self.alias.trait_def_id(interner)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn def_id(self) -> I::DefId {
|
pub fn def_id(self) -> I::DefId {
|
||||||
self.alias.def_id()
|
self.alias.def_id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,11 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||||
use rustc_data_structures::unify::{EqUnifyValue, UnifyKey};
|
use rustc_data_structures::unify::{EqUnifyValue, UnifyKey};
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable};
|
use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable};
|
||||||
use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
|
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use crate::Interner;
|
use crate::inherent::*;
|
||||||
use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, WithInfcx};
|
use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, TraitRef, WithInfcx};
|
||||||
|
|
||||||
use self::TyKind::*;
|
use self::TyKind::*;
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ pub enum TyKind<I: Interner> {
|
||||||
/// for `struct List<T>` and the args `[i32]`.
|
/// for `struct List<T>` and the args `[i32]`.
|
||||||
///
|
///
|
||||||
/// Note that generic parameters in fields only get lazily instantiated
|
/// Note that generic parameters in fields only get lazily instantiated
|
||||||
/// by using something like `adt_def.all_fields().map(|field| field.ty(tcx, args))`.
|
/// by using something like `adt_def.all_fields().map(|field| field.ty(interner, args))`.
|
||||||
Adt(I::AdtDef, I::GenericArgs),
|
Adt(I::AdtDef, I::GenericArgs),
|
||||||
|
|
||||||
/// An unsized FFI type that is opaque to Rust. Written as `extern type T`.
|
/// An unsized FFI type that is opaque to Rust. Written as `extern type T`.
|
||||||
|
@ -201,7 +201,7 @@ pub enum TyKind<I: Interner> {
|
||||||
/// A projection, opaque type, weak type alias, or inherent associated type.
|
/// A projection, opaque type, weak type alias, or inherent associated type.
|
||||||
/// All of these types are represented as pairs of def-id and args, and can
|
/// All of these types are represented as pairs of def-id and args, and can
|
||||||
/// be normalized, so they are grouped conceptually.
|
/// be normalized, so they are grouped conceptually.
|
||||||
Alias(AliasTyKind, I::AliasTy),
|
Alias(AliasTyKind, AliasTy<I>),
|
||||||
|
|
||||||
/// A type parameter; for example, `T` in `fn f<T>(x: T) {}`.
|
/// A type parameter; for example, `T` in `fn f<T>(x: T) {}`.
|
||||||
Param(I::ParamTy),
|
Param(I::ParamTy),
|
||||||
|
@ -422,6 +422,154 @@ impl<I: Interner> fmt::Debug for TyKind<I> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the projection of an associated, opaque, or lazy-type-alias type.
|
||||||
|
///
|
||||||
|
/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
|
||||||
|
/// * For an inherent projection, this would be `Ty::N<...>`.
|
||||||
|
/// * For an opaque type, there is no explicit syntax.
|
||||||
|
#[derive(derivative::Derivative)]
|
||||||
|
#[derivative(
|
||||||
|
Clone(bound = ""),
|
||||||
|
Copy(bound = ""),
|
||||||
|
Hash(bound = ""),
|
||||||
|
PartialEq(bound = ""),
|
||||||
|
Eq(bound = "")
|
||||||
|
)]
|
||||||
|
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
|
||||||
|
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
|
||||||
|
pub struct AliasTy<I: Interner> {
|
||||||
|
/// The parameters of the associated or opaque type.
|
||||||
|
///
|
||||||
|
/// For a projection, these are the generic parameters for the trait and the
|
||||||
|
/// GAT parameters, if there are any.
|
||||||
|
///
|
||||||
|
/// For an inherent projection, they consist of the self type and the GAT parameters,
|
||||||
|
/// if there are any.
|
||||||
|
///
|
||||||
|
/// For RPIT the generic parameters are for the generics of the function,
|
||||||
|
/// while for TAIT it is used for the generic parameters of the alias.
|
||||||
|
pub args: I::GenericArgs,
|
||||||
|
|
||||||
|
/// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether
|
||||||
|
/// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if
|
||||||
|
/// this is an opaque.
|
||||||
|
///
|
||||||
|
/// During codegen, `interner.type_of(def_id)` can be used to get the type of the
|
||||||
|
/// underlying type if the type is an opaque.
|
||||||
|
///
|
||||||
|
/// Note that if this is an associated type, this is not the `DefId` of the
|
||||||
|
/// `TraitRef` containing this associated type, which is in `interner.associated_item(def_id).container`,
|
||||||
|
/// aka. `interner.parent(def_id)`.
|
||||||
|
pub def_id: I::DefId,
|
||||||
|
|
||||||
|
/// This field exists to prevent the creation of `AliasTy` without using
|
||||||
|
/// [AliasTy::new].
|
||||||
|
pub(crate) _use_alias_ty_new_instead: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> AliasTy<I> {
|
||||||
|
pub fn new(
|
||||||
|
interner: I,
|
||||||
|
def_id: I::DefId,
|
||||||
|
args: impl IntoIterator<Item: Into<I::GenericArg>>,
|
||||||
|
) -> AliasTy<I> {
|
||||||
|
let args = interner.check_and_mk_args(def_id, args);
|
||||||
|
AliasTy { def_id, args, _use_alias_ty_new_instead: () }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kind(self, interner: I) -> AliasTyKind {
|
||||||
|
interner.alias_ty_kind(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether this alias type is an opaque.
|
||||||
|
pub fn is_opaque(self, interner: I) -> bool {
|
||||||
|
matches!(self.kind(interner), AliasTyKind::Opaque)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_ty(self, interner: I) -> I::Ty {
|
||||||
|
Ty::new_alias(interner, self.kind(interner), self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The following methods work only with (trait) associated type projections.
|
||||||
|
impl<I: Interner> AliasTy<I> {
|
||||||
|
pub fn self_ty(self) -> I::Ty {
|
||||||
|
self.args.type_at(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self {
|
||||||
|
AliasTy::new(
|
||||||
|
interner,
|
||||||
|
self.def_id,
|
||||||
|
[self_ty.into()].into_iter().chain(self.args.into_iter().skip(1)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn trait_def_id(self, interner: I) -> I::DefId {
|
||||||
|
assert_eq!(self.kind(interner), AliasTyKind::Projection, "expected a projection");
|
||||||
|
interner.parent(self.def_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts the underlying trait reference and own args from this projection.
|
||||||
|
/// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
|
||||||
|
/// then this function would return a `T: StreamingIterator` trait reference and
|
||||||
|
/// `['a]` as the own args.
|
||||||
|
pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef<I>, I::GenericArgsSlice) {
|
||||||
|
debug_assert_eq!(self.kind(interner), AliasTyKind::Projection);
|
||||||
|
interner.trait_ref_and_own_args_for_alias(self.def_id, self.args)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts the underlying trait reference from this projection.
|
||||||
|
/// For example, if this is a projection of `<T as Iterator>::Item`,
|
||||||
|
/// then this function would return a `T: Iterator` trait reference.
|
||||||
|
///
|
||||||
|
/// WARNING: This will drop the args for generic associated types
|
||||||
|
/// consider calling [Self::trait_ref_and_own_args] to get those
|
||||||
|
/// as well.
|
||||||
|
pub fn trait_ref(self, interner: I) -> TraitRef<I> {
|
||||||
|
self.trait_ref_and_own_args(interner).0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The following methods work only with inherent associated type projections.
|
||||||
|
impl<I: Interner> AliasTy<I> {
|
||||||
|
/// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that.
|
||||||
|
///
|
||||||
|
/// Does the following transformation:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m]
|
||||||
|
///
|
||||||
|
/// I_i impl args
|
||||||
|
/// P_j GAT args
|
||||||
|
/// ```
|
||||||
|
pub fn rebase_inherent_args_onto_impl(
|
||||||
|
self,
|
||||||
|
impl_args: I::GenericArgs,
|
||||||
|
interner: I,
|
||||||
|
) -> I::GenericArgs {
|
||||||
|
debug_assert_eq!(self.kind(interner), AliasTyKind::Inherent);
|
||||||
|
interner.mk_args_from_iter(impl_args.into_iter().chain(self.args.into_iter().skip(1)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> fmt::Debug for AliasTy<I> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
WithInfcx::with_no_infcx(self).fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<I: Interner> DebugWithInfcx<I> for AliasTy<I> {
|
||||||
|
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
|
||||||
|
this: WithInfcx<'_, Infcx, &Self>,
|
||||||
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> core::fmt::Result {
|
||||||
|
f.debug_struct("AliasTy")
|
||||||
|
.field("args", &this.map(|data| data.args))
|
||||||
|
.field("def_id", &this.data.def_id)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
|
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
|
||||||
pub enum IntTy {
|
pub enum IntTy {
|
||||||
|
|
|
@ -91,17 +91,21 @@ pub struct EscapeDefault(escape::EscapeIterInner<4>);
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn escape_default(c: u8) -> EscapeDefault {
|
pub fn escape_default(c: u8) -> EscapeDefault {
|
||||||
let mut data = [Char::Null; 4];
|
EscapeDefault::new(c)
|
||||||
let range = escape::escape_ascii_into(&mut data, c);
|
|
||||||
EscapeDefault(escape::EscapeIterInner::new(data, range))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EscapeDefault {
|
impl EscapeDefault {
|
||||||
pub(crate) fn empty() -> Self {
|
#[inline]
|
||||||
let data = [Char::Null; 4];
|
pub(crate) const fn new(c: u8) -> Self {
|
||||||
EscapeDefault(escape::EscapeIterInner::new(data, 0..0))
|
Self(escape::EscapeIterInner::ascii(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn empty() -> Self {
|
||||||
|
Self(escape::EscapeIterInner::empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub(crate) fn as_str(&self) -> &str {
|
pub(crate) fn as_str(&self) -> &str {
|
||||||
self.0.as_str()
|
self.0.as_str()
|
||||||
}
|
}
|
||||||
|
|
|
@ -449,10 +449,10 @@ impl char {
|
||||||
'\"' if args.escape_double_quote => EscapeDebug::backslash(ascii::Char::QuotationMark),
|
'\"' if args.escape_double_quote => EscapeDebug::backslash(ascii::Char::QuotationMark),
|
||||||
'\'' if args.escape_single_quote => EscapeDebug::backslash(ascii::Char::Apostrophe),
|
'\'' if args.escape_single_quote => EscapeDebug::backslash(ascii::Char::Apostrophe),
|
||||||
_ if args.escape_grapheme_extended && self.is_grapheme_extended() => {
|
_ if args.escape_grapheme_extended && self.is_grapheme_extended() => {
|
||||||
EscapeDebug::from_unicode(self.escape_unicode())
|
EscapeDebug::unicode(self)
|
||||||
}
|
}
|
||||||
_ if is_printable(self) => EscapeDebug::printable(self),
|
_ if is_printable(self) => EscapeDebug::printable(self),
|
||||||
_ => EscapeDebug::from_unicode(self.escape_unicode()),
|
_ => EscapeDebug::unicode(self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -555,9 +555,9 @@ impl char {
|
||||||
'\t' => EscapeDefault::backslash(ascii::Char::SmallT),
|
'\t' => EscapeDefault::backslash(ascii::Char::SmallT),
|
||||||
'\r' => EscapeDefault::backslash(ascii::Char::SmallR),
|
'\r' => EscapeDefault::backslash(ascii::Char::SmallR),
|
||||||
'\n' => EscapeDefault::backslash(ascii::Char::SmallN),
|
'\n' => EscapeDefault::backslash(ascii::Char::SmallN),
|
||||||
'\\' | '\'' | '"' => EscapeDefault::backslash(self.as_ascii().unwrap()),
|
'\\' | '\'' | '\"' => EscapeDefault::backslash(self.as_ascii().unwrap()),
|
||||||
'\x20'..='\x7e' => EscapeDefault::printable(self.as_ascii().unwrap()),
|
'\x20'..='\x7e' => EscapeDefault::printable(self.as_ascii().unwrap()),
|
||||||
_ => EscapeDefault::from_unicode(self.escape_unicode()),
|
_ => EscapeDefault::unicode(self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -152,10 +152,9 @@ pub const fn from_digit(num: u32, radix: u32) -> Option<char> {
|
||||||
pub struct EscapeUnicode(escape::EscapeIterInner<10>);
|
pub struct EscapeUnicode(escape::EscapeIterInner<10>);
|
||||||
|
|
||||||
impl EscapeUnicode {
|
impl EscapeUnicode {
|
||||||
fn new(chr: char) -> Self {
|
#[inline]
|
||||||
let mut data = [ascii::Char::Null; 10];
|
const fn new(c: char) -> Self {
|
||||||
let range = escape::escape_unicode_into(&mut data, chr);
|
Self(escape::EscapeIterInner::unicode(c))
|
||||||
Self(escape::EscapeIterInner::new(data, range))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,18 +218,19 @@ impl fmt::Display for EscapeUnicode {
|
||||||
pub struct EscapeDefault(escape::EscapeIterInner<10>);
|
pub struct EscapeDefault(escape::EscapeIterInner<10>);
|
||||||
|
|
||||||
impl EscapeDefault {
|
impl EscapeDefault {
|
||||||
fn printable(chr: ascii::Char) -> Self {
|
#[inline]
|
||||||
let data = [chr];
|
const fn printable(c: ascii::Char) -> Self {
|
||||||
Self(escape::EscapeIterInner::from_array(data))
|
Self(escape::EscapeIterInner::ascii(c.to_u8()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn backslash(chr: ascii::Char) -> Self {
|
#[inline]
|
||||||
let data = [ascii::Char::ReverseSolidus, chr];
|
const fn backslash(c: ascii::Char) -> Self {
|
||||||
Self(escape::EscapeIterInner::from_array(data))
|
Self(escape::EscapeIterInner::backslash(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_unicode(esc: EscapeUnicode) -> Self {
|
#[inline]
|
||||||
Self(esc.0)
|
const fn unicode(c: char) -> Self {
|
||||||
|
Self(escape::EscapeIterInner::unicode(c))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,23 +304,24 @@ enum EscapeDebugInner {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EscapeDebug {
|
impl EscapeDebug {
|
||||||
fn printable(chr: char) -> Self {
|
#[inline]
|
||||||
|
const fn printable(chr: char) -> Self {
|
||||||
Self(EscapeDebugInner::Char(chr))
|
Self(EscapeDebugInner::Char(chr))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn backslash(chr: ascii::Char) -> Self {
|
#[inline]
|
||||||
let data = [ascii::Char::ReverseSolidus, chr];
|
const fn backslash(c: ascii::Char) -> Self {
|
||||||
let iter = escape::EscapeIterInner::from_array(data);
|
Self(EscapeDebugInner::Bytes(escape::EscapeIterInner::backslash(c)))
|
||||||
Self(EscapeDebugInner::Bytes(iter))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_unicode(esc: EscapeUnicode) -> Self {
|
#[inline]
|
||||||
Self(EscapeDebugInner::Bytes(esc.0))
|
const fn unicode(c: char) -> Self {
|
||||||
|
Self(EscapeDebugInner::Bytes(escape::EscapeIterInner::unicode(c)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn clear(&mut self) {
|
fn clear(&mut self) {
|
||||||
let bytes = escape::EscapeIterInner::from_array([]);
|
self.0 = EscapeDebugInner::Bytes(escape::EscapeIterInner::empty());
|
||||||
self.0 = EscapeDebugInner::Bytes(bytes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,6 +340,7 @@ impl Iterator for EscapeDebug {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
let n = self.len();
|
let n = self.len();
|
||||||
(n, Some(n))
|
(n, Some(n))
|
||||||
|
|
|
@ -6,56 +6,79 @@ use crate::ops::Range;
|
||||||
|
|
||||||
const HEX_DIGITS: [ascii::Char; 16] = *b"0123456789abcdef".as_ascii().unwrap();
|
const HEX_DIGITS: [ascii::Char; 16] = *b"0123456789abcdef".as_ascii().unwrap();
|
||||||
|
|
||||||
/// Escapes a byte into provided buffer; returns length of escaped
|
#[inline]
|
||||||
/// representation.
|
const fn backslash<const N: usize>(a: ascii::Char) -> ([ascii::Char; N], Range<u8>) {
|
||||||
pub(crate) fn escape_ascii_into(output: &mut [ascii::Char; 4], byte: u8) -> Range<u8> {
|
const { assert!(N >= 2) };
|
||||||
#[inline]
|
|
||||||
fn backslash(a: ascii::Char) -> ([ascii::Char; 4], u8) {
|
|
||||||
([ascii::Char::ReverseSolidus, a, ascii::Char::Null, ascii::Char::Null], 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
let (data, len) = match byte {
|
let mut output = [ascii::Char::Null; N];
|
||||||
|
|
||||||
|
output[0] = ascii::Char::ReverseSolidus;
|
||||||
|
output[1] = a;
|
||||||
|
|
||||||
|
(output, 0..2)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Escapes an ASCII character.
|
||||||
|
///
|
||||||
|
/// Returns a buffer and the length of the escaped representation.
|
||||||
|
const fn escape_ascii<const N: usize>(byte: u8) -> ([ascii::Char; N], Range<u8>) {
|
||||||
|
const { assert!(N >= 4) };
|
||||||
|
|
||||||
|
match byte {
|
||||||
b'\t' => backslash(ascii::Char::SmallT),
|
b'\t' => backslash(ascii::Char::SmallT),
|
||||||
b'\r' => backslash(ascii::Char::SmallR),
|
b'\r' => backslash(ascii::Char::SmallR),
|
||||||
b'\n' => backslash(ascii::Char::SmallN),
|
b'\n' => backslash(ascii::Char::SmallN),
|
||||||
b'\\' => backslash(ascii::Char::ReverseSolidus),
|
b'\\' => backslash(ascii::Char::ReverseSolidus),
|
||||||
b'\'' => backslash(ascii::Char::Apostrophe),
|
b'\'' => backslash(ascii::Char::Apostrophe),
|
||||||
b'\"' => backslash(ascii::Char::QuotationMark),
|
b'\"' => backslash(ascii::Char::QuotationMark),
|
||||||
_ => {
|
byte => {
|
||||||
if let Some(a) = byte.as_ascii()
|
let mut output = [ascii::Char::Null; N];
|
||||||
|
|
||||||
|
if let Some(c) = byte.as_ascii()
|
||||||
&& !byte.is_ascii_control()
|
&& !byte.is_ascii_control()
|
||||||
{
|
{
|
||||||
([a, ascii::Char::Null, ascii::Char::Null, ascii::Char::Null], 1)
|
output[0] = c;
|
||||||
|
(output, 0..1)
|
||||||
} else {
|
} else {
|
||||||
let hi = HEX_DIGITS[usize::from(byte >> 4)];
|
let hi = HEX_DIGITS[(byte >> 4) as usize];
|
||||||
let lo = HEX_DIGITS[usize::from(byte & 0xf)];
|
let lo = HEX_DIGITS[(byte & 0xf) as usize];
|
||||||
([ascii::Char::ReverseSolidus, ascii::Char::SmallX, hi, lo], 4)
|
|
||||||
|
output[0] = ascii::Char::ReverseSolidus;
|
||||||
|
output[1] = ascii::Char::SmallX;
|
||||||
|
output[2] = hi;
|
||||||
|
output[3] = lo;
|
||||||
|
|
||||||
|
(output, 0..4)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
*output = data;
|
|
||||||
0..len
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Escapes a character into provided buffer using `\u{NNNN}` representation.
|
/// Escapes a character `\u{NNNN}` representation.
|
||||||
pub(crate) fn escape_unicode_into(output: &mut [ascii::Char; 10], ch: char) -> Range<u8> {
|
///
|
||||||
|
/// Returns a buffer and the length of the escaped representation.
|
||||||
|
const fn escape_unicode<const N: usize>(c: char) -> ([ascii::Char; N], Range<u8>) {
|
||||||
|
const { assert!(N >= 10 && N < u8::MAX as usize) };
|
||||||
|
|
||||||
|
let c = u32::from(c);
|
||||||
|
|
||||||
|
// OR-ing `1` ensures that for `c == 0` the code computes that
|
||||||
|
// one digit should be printed.
|
||||||
|
let start = (c | 1).leading_zeros() as usize / 4 - 2;
|
||||||
|
|
||||||
|
let mut output = [ascii::Char::Null; N];
|
||||||
|
output[3] = HEX_DIGITS[((c >> 20) & 15) as usize];
|
||||||
|
output[4] = HEX_DIGITS[((c >> 16) & 15) as usize];
|
||||||
|
output[5] = HEX_DIGITS[((c >> 12) & 15) as usize];
|
||||||
|
output[6] = HEX_DIGITS[((c >> 8) & 15) as usize];
|
||||||
|
output[7] = HEX_DIGITS[((c >> 4) & 15) as usize];
|
||||||
|
output[8] = HEX_DIGITS[((c >> 0) & 15) as usize];
|
||||||
output[9] = ascii::Char::RightCurlyBracket;
|
output[9] = ascii::Char::RightCurlyBracket;
|
||||||
|
output[start + 0] = ascii::Char::ReverseSolidus;
|
||||||
|
output[start + 1] = ascii::Char::SmallU;
|
||||||
|
output[start + 2] = ascii::Char::LeftCurlyBracket;
|
||||||
|
|
||||||
let ch = ch as u32;
|
(output, (start as u8)..(N as u8))
|
||||||
output[3] = HEX_DIGITS[((ch >> 20) & 15) as usize];
|
|
||||||
output[4] = HEX_DIGITS[((ch >> 16) & 15) as usize];
|
|
||||||
output[5] = HEX_DIGITS[((ch >> 12) & 15) as usize];
|
|
||||||
output[6] = HEX_DIGITS[((ch >> 8) & 15) as usize];
|
|
||||||
output[7] = HEX_DIGITS[((ch >> 4) & 15) as usize];
|
|
||||||
output[8] = HEX_DIGITS[((ch >> 0) & 15) as usize];
|
|
||||||
|
|
||||||
// or-ing 1 ensures that for ch==0 the code computes that one digit should
|
|
||||||
// be printed.
|
|
||||||
let start = (ch | 1).leading_zeros() as usize / 4 - 2;
|
|
||||||
const UNICODE_ESCAPE_PREFIX: &[ascii::Char; 3] = b"\\u{".as_ascii().unwrap();
|
|
||||||
output[start..][..3].copy_from_slice(UNICODE_ESCAPE_PREFIX);
|
|
||||||
|
|
||||||
(start as u8)..10
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An iterator over an fixed-size array.
|
/// An iterator over an fixed-size array.
|
||||||
|
@ -65,45 +88,63 @@ pub(crate) fn escape_unicode_into(output: &mut [ascii::Char; 10], ch: char) -> R
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) struct EscapeIterInner<const N: usize> {
|
pub(crate) struct EscapeIterInner<const N: usize> {
|
||||||
// The element type ensures this is always ASCII, and thus also valid UTF-8.
|
// The element type ensures this is always ASCII, and thus also valid UTF-8.
|
||||||
pub(crate) data: [ascii::Char; N],
|
data: [ascii::Char; N],
|
||||||
|
|
||||||
// Invariant: alive.start <= alive.end <= N.
|
// Invariant: `alive.start <= alive.end <= N`
|
||||||
pub(crate) alive: Range<u8>,
|
alive: Range<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const N: usize> EscapeIterInner<N> {
|
impl<const N: usize> EscapeIterInner<N> {
|
||||||
pub fn new(data: [ascii::Char; N], alive: Range<u8>) -> Self {
|
pub const fn backslash(c: ascii::Char) -> Self {
|
||||||
const { assert!(N < 256) };
|
let (data, range) = backslash(c);
|
||||||
debug_assert!(alive.start <= alive.end && usize::from(alive.end) <= N, "{alive:?}");
|
Self { data, alive: range }
|
||||||
Self { data, alive }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_array<const M: usize>(array: [ascii::Char; M]) -> Self {
|
pub const fn ascii(c: u8) -> Self {
|
||||||
const { assert!(M <= N) };
|
let (data, range) = escape_ascii(c);
|
||||||
|
Self { data, alive: range }
|
||||||
let mut data = [ascii::Char::Null; N];
|
|
||||||
data[..M].copy_from_slice(&array);
|
|
||||||
Self::new(data, 0..M as u8)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const fn unicode(c: char) -> Self {
|
||||||
|
let (data, range) = escape_unicode(c);
|
||||||
|
Self { data, alive: range }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn empty() -> Self {
|
||||||
|
Self { data: [ascii::Char::Null; N], alive: 0..0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn as_ascii(&self) -> &[ascii::Char] {
|
pub fn as_ascii(&self) -> &[ascii::Char] {
|
||||||
&self.data[usize::from(self.alive.start)..usize::from(self.alive.end)]
|
// SAFETY: `self.alive` is guaranteed to be a valid range for indexing `self.data`.
|
||||||
|
unsafe {
|
||||||
|
self.data.get_unchecked(usize::from(self.alive.start)..usize::from(self.alive.end))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn as_str(&self) -> &str {
|
pub fn as_str(&self) -> &str {
|
||||||
self.as_ascii().as_str()
|
self.as_ascii().as_str()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
usize::from(self.alive.end - self.alive.start)
|
usize::from(self.alive.end - self.alive.start)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next(&mut self) -> Option<u8> {
|
pub fn next(&mut self) -> Option<u8> {
|
||||||
self.alive.next().map(|i| self.data[usize::from(i)].to_u8())
|
let i = self.alive.next()?;
|
||||||
|
|
||||||
|
// SAFETY: `i` is guaranteed to be a valid index for `self.data`.
|
||||||
|
unsafe { Some(self.data.get_unchecked(usize::from(i)).to_u8()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next_back(&mut self) -> Option<u8> {
|
pub fn next_back(&mut self) -> Option<u8> {
|
||||||
self.alive.next_back().map(|i| self.data[usize::from(i)].to_u8())
|
let i = self.alive.next_back()?;
|
||||||
|
|
||||||
|
// SAFETY: `i` is guaranteed to be a valid index for `self.data`.
|
||||||
|
unsafe { Some(self.data.get_unchecked(usize::from(i)).to_u8()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
pub fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
||||||
|
|
|
@ -584,11 +584,11 @@ macro_rules! uint_impl {
|
||||||
// Thus, rather than using `overflowing_sub` that produces a wrapping
|
// Thus, rather than using `overflowing_sub` that produces a wrapping
|
||||||
// subtraction, check it ourself so we can use an unchecked one.
|
// subtraction, check it ourself so we can use an unchecked one.
|
||||||
|
|
||||||
if self >= rhs {
|
if self < rhs {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
// SAFETY: just checked this can't overflow
|
// SAFETY: just checked this can't overflow
|
||||||
Some(unsafe { intrinsics::unchecked_sub(self, rhs) })
|
Some(unsafe { intrinsics::unchecked_sub(self, rhs) })
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,21 +87,18 @@ cfg_if::cfg_if! {
|
||||||
// /memory/aligned_memory.cc
|
// /memory/aligned_memory.cc
|
||||||
libc::memalign(layout.align(), layout.size()) as *mut u8
|
libc::memalign(layout.align(), layout.size()) as *mut u8
|
||||||
}
|
}
|
||||||
} else if #[cfg(target_os = "wasi")] {
|
|
||||||
#[inline]
|
|
||||||
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
|
|
||||||
// C11 aligned_alloc requires that the size be a multiple of the alignment.
|
|
||||||
// Layout already checks that the size rounded up doesn't overflow isize::MAX.
|
|
||||||
let align = layout.align();
|
|
||||||
let size = layout.size().next_multiple_of(align);
|
|
||||||
libc::aligned_alloc(align, size) as *mut u8
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
|
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
|
||||||
let mut out = ptr::null_mut();
|
let mut out = ptr::null_mut();
|
||||||
// posix_memalign requires that the alignment be a multiple of `sizeof(void*)`.
|
// We prefer posix_memalign over aligned_malloc since with aligned_malloc,
|
||||||
// Since these are all powers of 2, we can just use max.
|
// implementations are making almost arbitrary choices for which alignments are
|
||||||
|
// "supported", making it hard to use. For instance, some implementations require the
|
||||||
|
// size to be a multiple of the alignment (wasi emmalloc), while others require the
|
||||||
|
// alignment to be at least the pointer size (Illumos, macOS) -- which may or may not be
|
||||||
|
// standards-compliant, but that does not help us.
|
||||||
|
// posix_memalign only has one, clear requirement: that the alignment be a multiple of
|
||||||
|
// `sizeof(void*)`. Since these are all powers of 2, we can just use max.
|
||||||
let align = layout.align().max(crate::mem::size_of::<usize>());
|
let align = layout.align().max(crate::mem::size_of::<usize>());
|
||||||
let ret = libc::posix_memalign(&mut out, align, layout.size());
|
let ret = libc::posix_memalign(&mut out, align, layout.size());
|
||||||
if ret != 0 { ptr::null_mut() } else { out as *mut u8 }
|
if ret != 0 { ptr::null_mut() } else { out as *mut u8 }
|
||||||
|
|
|
@ -8,6 +8,8 @@ compiler-docs = true
|
||||||
# where adding `debug!()` appears to do nothing.
|
# where adding `debug!()` appears to do nothing.
|
||||||
# However, it makes running the compiler slightly slower.
|
# However, it makes running the compiler slightly slower.
|
||||||
debug-logging = true
|
debug-logging = true
|
||||||
|
# Get actually-useful information from backtraces, profiling, etc. with minimal added bytes
|
||||||
|
debuginfo-level = "line-tables-only"
|
||||||
# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
|
# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
|
||||||
incremental = true
|
incremental = true
|
||||||
# Print backtrace on internal compiler errors during bootstrap
|
# Print backtrace on internal compiler errors during bootstrap
|
||||||
|
|
|
@ -26,7 +26,9 @@ use crate::core::build_steps::tool::{self, Tool};
|
||||||
use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
|
use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
|
||||||
use crate::core::config::TargetSelection;
|
use crate::core::config::TargetSelection;
|
||||||
use crate::utils::channel::{self, Info};
|
use crate::utils::channel::{self, Info};
|
||||||
use crate::utils::helpers::{exe, is_dylib, output, t, target_supports_cranelift_backend, timeit};
|
use crate::utils::helpers::{
|
||||||
|
exe, is_dylib, move_file, output, t, target_supports_cranelift_backend, timeit,
|
||||||
|
};
|
||||||
use crate::utils::tarball::{GeneratedTarball, OverlayKind, Tarball};
|
use crate::utils::tarball::{GeneratedTarball, OverlayKind, Tarball};
|
||||||
use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS};
|
use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS};
|
||||||
|
|
||||||
|
@ -2024,7 +2026,7 @@ impl Step for Extended {
|
||||||
builder.run(&mut cmd);
|
builder.run(&mut cmd);
|
||||||
|
|
||||||
if !builder.config.dry_run() {
|
if !builder.config.dry_run() {
|
||||||
t!(fs::rename(exe.join(&filename), distdir(builder).join(&filename)));
|
t!(move_file(exe.join(&filename), distdir(builder).join(&filename)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use build_helper::ci::CiEnv;
|
||||||
use build_helper::stage0_parser::VersionMetadata;
|
use build_helper::stage0_parser::VersionMetadata;
|
||||||
use xz2::bufread::XzDecoder;
|
use xz2::bufread::XzDecoder;
|
||||||
|
|
||||||
use crate::utils::helpers::{check_run, exe, program_out_of_date};
|
use crate::utils::helpers::{check_run, exe, move_file, program_out_of_date};
|
||||||
use crate::{core::build_steps::llvm::detect_llvm_sha, utils::helpers::hex_encode};
|
use crate::{core::build_steps::llvm::detect_llvm_sha, utils::helpers::hex_encode};
|
||||||
use crate::{t, Config};
|
use crate::{t, Config};
|
||||||
|
|
||||||
|
@ -209,7 +209,7 @@ impl Config {
|
||||||
None => panic!("no protocol in {url}"),
|
None => panic!("no protocol in {url}"),
|
||||||
}
|
}
|
||||||
t!(
|
t!(
|
||||||
std::fs::rename(&tempfile, dest_path),
|
move_file(&tempfile, dest_path),
|
||||||
format!("failed to rename {tempfile:?} to {dest_path:?}")
|
format!("failed to rename {tempfile:?} to {dest_path:?}")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -313,7 +313,7 @@ impl Config {
|
||||||
if src_path.is_dir() && dst_path.exists() {
|
if src_path.is_dir() && dst_path.exists() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
t!(fs::rename(src_path, dst_path));
|
t!(move_file(src_path, dst_path));
|
||||||
}
|
}
|
||||||
let dst_dir = dst.join(directory_prefix);
|
let dst_dir = dst.join(directory_prefix);
|
||||||
if dst_dir.exists() {
|
if dst_dir.exists() {
|
||||||
|
|
|
@ -180,4 +180,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
|
||||||
severity: ChangeSeverity::Info,
|
severity: ChangeSeverity::Info,
|
||||||
summary: "New option `build.lldb` that will override the default lldb binary path used in debuginfo tests",
|
summary: "New option `build.lldb` that will override the default lldb binary path used in debuginfo tests",
|
||||||
},
|
},
|
||||||
|
ChangeInfo {
|
||||||
|
change_id: 123337,
|
||||||
|
severity: ChangeSeverity::Info,
|
||||||
|
summary: r#"The compiler profile now defaults to rust.debuginfo-level = "line-tables-only""#,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -150,6 +150,21 @@ pub fn symlink_dir(config: &Config, original: &Path, link: &Path) -> io::Result<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Rename a file if from and to are in the same filesystem or
|
||||||
|
/// copy and remove the file otherwise
|
||||||
|
pub fn move_file<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
|
||||||
|
match fs::rename(&from, &to) {
|
||||||
|
// FIXME: Once `ErrorKind::CrossesDevices` is stabilized use
|
||||||
|
// if e.kind() == io::ErrorKind::CrossesDevices {
|
||||||
|
#[cfg(unix)]
|
||||||
|
Err(e) if e.raw_os_error() == Some(libc::EXDEV) => {
|
||||||
|
std::fs::copy(&from, &to)?;
|
||||||
|
std::fs::remove_file(&from)
|
||||||
|
}
|
||||||
|
r => r,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn forcing_clang_based_tests() -> bool {
|
pub fn forcing_clang_based_tests() -> bool {
|
||||||
if let Some(var) = env::var_os("RUSTBUILD_FORCE_CLANG_BASED_TESTS") {
|
if let Some(var) = env::var_os("RUSTBUILD_FORCE_CLANG_BASED_TESTS") {
|
||||||
match &var.to_string_lossy().to_lowercase()[..] {
|
match &var.to_string_lossy().to_lowercase()[..] {
|
||||||
|
|
|
@ -13,7 +13,7 @@ use std::{
|
||||||
use crate::core::builder::Builder;
|
use crate::core::builder::Builder;
|
||||||
use crate::core::{build_steps::dist::distdir, builder::Kind};
|
use crate::core::{build_steps::dist::distdir, builder::Kind};
|
||||||
use crate::utils::channel;
|
use crate::utils::channel;
|
||||||
use crate::utils::helpers::t;
|
use crate::utils::helpers::{move_file, t};
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub(crate) enum OverlayKind {
|
pub(crate) enum OverlayKind {
|
||||||
|
@ -284,7 +284,7 @@ impl<'a> Tarball<'a> {
|
||||||
// name, not "image". We rename the image directory just before passing
|
// name, not "image". We rename the image directory just before passing
|
||||||
// into rust-installer.
|
// into rust-installer.
|
||||||
let dest = self.temp_dir.join(self.package_name());
|
let dest = self.temp_dir.join(self.package_name());
|
||||||
t!(std::fs::rename(&self.image_dir, &dest));
|
t!(move_file(&self.image_dir, &dest));
|
||||||
|
|
||||||
self.run(|this, cmd| {
|
self.run(|this, cmd| {
|
||||||
let distdir = distdir(this.builder);
|
let distdir = distdir(this.builder);
|
||||||
|
|
|
@ -40,6 +40,8 @@ include:
|
||||||
of a delimited expression, delimited expressions are generally combinable,
|
of a delimited expression, delimited expressions are generally combinable,
|
||||||
regardless of the number of members. Previously only applied with exactly
|
regardless of the number of members. Previously only applied with exactly
|
||||||
one member (except for closures with explicit blocks).
|
one member (except for closures with explicit blocks).
|
||||||
|
- When line-breaking a binary operator, if the first operand spans multiple
|
||||||
|
lines, use the base indentation of the last line.
|
||||||
- Miscellaneous `rustfmt` bugfixes.
|
- Miscellaneous `rustfmt` bugfixes.
|
||||||
- Use version-sort (sort `x8`, `x16`, `x32`, `x64`, `x128` in that order).
|
- Use version-sort (sort `x8`, `x16`, `x32`, `x64`, `x128` in that order).
|
||||||
- Change "ASCIIbetical" sort to Unicode-aware "non-lowercase before lowercase".
|
- Change "ASCIIbetical" sort to Unicode-aware "non-lowercase before lowercase".
|
||||||
|
|
|
@ -328,6 +328,37 @@ foo_bar
|
||||||
Prefer line-breaking at an assignment operator (either `=` or `+=`, etc.) rather
|
Prefer line-breaking at an assignment operator (either `=` or `+=`, etc.) rather
|
||||||
than at other binary operators.
|
than at other binary operators.
|
||||||
|
|
||||||
|
If line-breaking at a binary operator (including assignment operators) where the
|
||||||
|
first operand spans multiple lines, use the base indentation of the *last*
|
||||||
|
line of the first operand, and indent relative to that:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
impl SomeType {
|
||||||
|
fn method(&mut self) {
|
||||||
|
self.array[array_index as usize]
|
||||||
|
.as_mut()
|
||||||
|
.expect("thing must exist")
|
||||||
|
.extra_info =
|
||||||
|
long_long_long_long_long_long_long_long_long_long_long_long_long_long_long;
|
||||||
|
|
||||||
|
self.array[array_index as usize]
|
||||||
|
.as_mut()
|
||||||
|
.expect("thing must exist")
|
||||||
|
.extra_info
|
||||||
|
+ long_long_long_long_long_long_long_long_long_long_long_long_long_long_long;
|
||||||
|
|
||||||
|
self.array[array_index as usize]
|
||||||
|
.as_mut()
|
||||||
|
.expect("thing must exist")
|
||||||
|
.extra_info = Some(ExtraInfo {
|
||||||
|
parent,
|
||||||
|
count: count as u16,
|
||||||
|
children: children.into_boxed_slice(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Casts (`as`)
|
### Casts (`as`)
|
||||||
|
|
||||||
Format `as` casts like a binary operator. In particular, always include spaces
|
Format `as` casts like a binary operator. In particular, always include spaces
|
||||||
|
|
|
@ -1424,6 +1424,10 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> O
|
||||||
if let Some(impls) = cx.cache().impls.get(&did) {
|
if let Some(impls) = cx.cache().impls.get(&did) {
|
||||||
for i in impls {
|
for i in impls {
|
||||||
let impl_ = i.inner_impl();
|
let impl_ = i.inner_impl();
|
||||||
|
if impl_.polarity != ty::ImplPolarity::Positive {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) {
|
if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) {
|
||||||
// Two different types might have the same did,
|
// Two different types might have the same did,
|
||||||
// without actually being the same.
|
// without actually being the same.
|
||||||
|
@ -1459,6 +1463,10 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
|
||||||
|
|
||||||
for i in impls {
|
for i in impls {
|
||||||
let impl_ = i.inner_impl();
|
let impl_ = i.inner_impl();
|
||||||
|
if impl_.polarity != ty::ImplPolarity::Positive {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) {
|
if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) {
|
||||||
// Two different types might have the same did,
|
// Two different types might have the same did,
|
||||||
// without actually being the same.
|
// without actually being the same.
|
||||||
|
|
|
@ -2478,6 +2478,15 @@ impl<'test> TestCx<'test> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let set_mir_dump_dir = |rustc: &mut Command| {
|
||||||
|
let mir_dump_dir = self.get_mir_dump_dir();
|
||||||
|
remove_and_create_dir_all(&mir_dump_dir);
|
||||||
|
let mut dir_opt = "-Zdump-mir-dir=".to_string();
|
||||||
|
dir_opt.push_str(mir_dump_dir.to_str().unwrap());
|
||||||
|
debug!("dir_opt: {:?}", dir_opt);
|
||||||
|
rustc.arg(dir_opt);
|
||||||
|
};
|
||||||
|
|
||||||
match self.config.mode {
|
match self.config.mode {
|
||||||
Incremental => {
|
Incremental => {
|
||||||
// If we are extracting and matching errors in the new
|
// If we are extracting and matching errors in the new
|
||||||
|
@ -2532,13 +2541,7 @@ impl<'test> TestCx<'test> {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mir_dump_dir = self.get_mir_dump_dir();
|
set_mir_dump_dir(&mut rustc);
|
||||||
remove_and_create_dir_all(&mir_dump_dir);
|
|
||||||
let mut dir_opt = "-Zdump-mir-dir=".to_string();
|
|
||||||
dir_opt.push_str(mir_dump_dir.to_str().unwrap());
|
|
||||||
debug!("dir_opt: {:?}", dir_opt);
|
|
||||||
|
|
||||||
rustc.arg(dir_opt);
|
|
||||||
}
|
}
|
||||||
CoverageMap => {
|
CoverageMap => {
|
||||||
rustc.arg("-Cinstrument-coverage");
|
rustc.arg("-Cinstrument-coverage");
|
||||||
|
@ -2560,8 +2563,11 @@ impl<'test> TestCx<'test> {
|
||||||
Assembly | Codegen => {
|
Assembly | Codegen => {
|
||||||
rustc.arg("-Cdebug-assertions=no");
|
rustc.arg("-Cdebug-assertions=no");
|
||||||
}
|
}
|
||||||
|
Crashes => {
|
||||||
|
set_mir_dump_dir(&mut rustc);
|
||||||
|
}
|
||||||
RunPassValgrind | Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake
|
RunPassValgrind | Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake
|
||||||
| CodegenUnits | JsDocTest | Crashes => {
|
| CodegenUnits | JsDocTest => {
|
||||||
// do not use JSON output
|
// do not use JSON output
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,10 @@ enum EnvironmentCmd {
|
||||||
#[arg(long, default_value = "opt-artifacts")]
|
#[arg(long, default_value = "opt-artifacts")]
|
||||||
artifact_dir: Utf8PathBuf,
|
artifact_dir: Utf8PathBuf,
|
||||||
|
|
||||||
|
/// Checkout directory of `rustc-perf`, it will be fetched automatically if unspecified.
|
||||||
|
#[arg(long)]
|
||||||
|
rustc_perf_checkout_dir: Option<Utf8PathBuf>,
|
||||||
|
|
||||||
/// Is LLVM for `rustc` built in shared library mode?
|
/// Is LLVM for `rustc` built in shared library mode?
|
||||||
#[arg(long, default_value_t = true)]
|
#[arg(long, default_value_t = true)]
|
||||||
llvm_shared: bool,
|
llvm_shared: bool,
|
||||||
|
@ -109,6 +113,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
|
||||||
llvm_dir,
|
llvm_dir,
|
||||||
python,
|
python,
|
||||||
artifact_dir,
|
artifact_dir,
|
||||||
|
rustc_perf_checkout_dir,
|
||||||
llvm_shared,
|
llvm_shared,
|
||||||
use_bolt,
|
use_bolt,
|
||||||
skipped_tests,
|
skipped_tests,
|
||||||
|
@ -121,6 +126,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
|
||||||
.host_llvm_dir(llvm_dir)
|
.host_llvm_dir(llvm_dir)
|
||||||
.artifact_dir(artifact_dir)
|
.artifact_dir(artifact_dir)
|
||||||
.build_dir(checkout_dir)
|
.build_dir(checkout_dir)
|
||||||
|
.prebuilt_rustc_perf(rustc_perf_checkout_dir)
|
||||||
.shared_llvm(llvm_shared)
|
.shared_llvm(llvm_shared)
|
||||||
.use_bolt(use_bolt)
|
.use_bolt(use_bolt)
|
||||||
.skipped_tests(skipped_tests)
|
.skipped_tests(skipped_tests)
|
||||||
|
|
|
@ -40,12 +40,17 @@ pub fn target() -> String {
|
||||||
|
|
||||||
/// Check if target is windows-like.
|
/// Check if target is windows-like.
|
||||||
pub fn is_windows() -> bool {
|
pub fn is_windows() -> bool {
|
||||||
env::var_os("IS_WINDOWS").is_some()
|
target().contains("windows")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if target uses msvc.
|
/// Check if target uses msvc.
|
||||||
pub fn is_msvc() -> bool {
|
pub fn is_msvc() -> bool {
|
||||||
env::var_os("IS_MSVC").is_some()
|
target().contains("msvc")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if target uses macOS.
|
||||||
|
pub fn is_darwin() -> bool {
|
||||||
|
target().contains("darwin")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a path to a static library under `$TMPDIR` given the library name. This will return a
|
/// Construct a path to a static library under `$TMPDIR` given the library name. This will return a
|
||||||
|
@ -59,6 +64,12 @@ pub fn python_command() -> Command {
|
||||||
Command::new(python_path)
|
Command::new(python_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn htmldocck() -> Command {
|
||||||
|
let mut python = python_command();
|
||||||
|
python.arg(source_path().join("src/etc/htmldocck.py"));
|
||||||
|
python
|
||||||
|
}
|
||||||
|
|
||||||
pub fn source_path() -> PathBuf {
|
pub fn source_path() -> PathBuf {
|
||||||
std::env::var("S").expect("S variable does not exist").into()
|
std::env::var("S").expect("S variable does not exist").into()
|
||||||
}
|
}
|
||||||
|
@ -82,9 +93,47 @@ pub fn static_lib_name(name: &str) -> String {
|
||||||
// endif
|
// endif
|
||||||
// endif
|
// endif
|
||||||
// ```
|
// ```
|
||||||
assert!(!name.contains(char::is_whitespace), "name cannot contain whitespace");
|
assert!(!name.contains(char::is_whitespace), "static library name cannot contain whitespace");
|
||||||
|
|
||||||
if target().contains("msvc") { format!("{name}.lib") } else { format!("lib{name}.a") }
|
if is_msvc() { format!("{name}.lib") } else { format!("lib{name}.a") }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct a path to a dynamic library under `$TMPDIR` given the library name. This will return a
|
||||||
|
/// path with `$TMPDIR` joined with platform-and-compiler-specific library name.
|
||||||
|
pub fn dynamic_lib(name: &str) -> PathBuf {
|
||||||
|
tmp_dir().join(dynamic_lib_name(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct the dynamic library name based on the platform.
|
||||||
|
pub fn dynamic_lib_name(name: &str) -> String {
|
||||||
|
// See tools.mk (irrelevant lines omitted):
|
||||||
|
//
|
||||||
|
// ```makefile
|
||||||
|
// ifeq ($(UNAME),Darwin)
|
||||||
|
// DYLIB = $(TMPDIR)/lib$(1).dylib
|
||||||
|
// else
|
||||||
|
// ifdef IS_WINDOWS
|
||||||
|
// DYLIB = $(TMPDIR)/$(1).dll
|
||||||
|
// else
|
||||||
|
// DYLIB = $(TMPDIR)/lib$(1).so
|
||||||
|
// endif
|
||||||
|
// endif
|
||||||
|
// ```
|
||||||
|
assert!(!name.contains(char::is_whitespace), "dynamic library name cannot contain whitespace");
|
||||||
|
|
||||||
|
if is_darwin() {
|
||||||
|
format!("lib{name}.dylib")
|
||||||
|
} else if is_windows() {
|
||||||
|
format!("{name}.dll")
|
||||||
|
} else {
|
||||||
|
format!("lib{name}.so")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct a path to a rust library (rlib) under `$TMPDIR` given the library name. This will return a
|
||||||
|
/// path with `$TMPDIR` joined with the library name.
|
||||||
|
pub fn rust_lib(name: &str) -> PathBuf {
|
||||||
|
tmp_dir().join(format!("lib{name}.rlib"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct the binary name based on platform.
|
/// Construct the binary name based on platform.
|
||||||
|
|
|
@ -91,7 +91,7 @@ impl Rustc {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specify path to the output file.
|
/// Specify path to the output file. Equivalent to `-o`` in rustc.
|
||||||
pub fn output<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
|
pub fn output<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
|
||||||
self.cmd.arg("-o");
|
self.cmd.arg("-o");
|
||||||
self.cmd.arg(path.as_ref());
|
self.cmd.arg(path.as_ref());
|
||||||
|
@ -150,6 +150,13 @@ impl Rustc {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a directory to the library search path. Equivalent to `-L`` in rustc.
|
||||||
|
pub fn library_search_path<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
|
||||||
|
self.cmd.arg("-L");
|
||||||
|
self.cmd.arg(path.as_ref());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Specify the edition year.
|
/// Specify the edition year.
|
||||||
pub fn edition(&mut self, edition: &str) -> &mut Self {
|
pub fn edition(&mut self, edition: &str) -> &mut Self {
|
||||||
self.cmd.arg("--edition");
|
self.cmd.arg("--edition");
|
||||||
|
|
|
@ -739,8 +739,8 @@ impl<'a> FmtVisitor<'a> {
|
||||||
(_, Const(..)) => Ordering::Greater,
|
(_, Const(..)) => Ordering::Greater,
|
||||||
(MacCall(..), _) => Ordering::Less,
|
(MacCall(..), _) => Ordering::Less,
|
||||||
(_, MacCall(..)) => Ordering::Greater,
|
(_, MacCall(..)) => Ordering::Greater,
|
||||||
(Delegation(..), _) => Ordering::Less,
|
(Delegation(..), _) | (DelegationMac(..), _) => Ordering::Less,
|
||||||
(_, Delegation(..)) => Ordering::Greater,
|
(_, Delegation(..)) | (_, DelegationMac(..)) => Ordering::Greater,
|
||||||
});
|
});
|
||||||
let mut prev_kind = None;
|
let mut prev_kind = None;
|
||||||
for (buf, item) in buffer {
|
for (buf, item) in buffer {
|
||||||
|
|
|
@ -586,7 +586,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
||||||
);
|
);
|
||||||
self.push_rewrite(item.span, rewrite);
|
self.push_rewrite(item.span, rewrite);
|
||||||
}
|
}
|
||||||
ast::ItemKind::Delegation(..) => {
|
ast::ItemKind::Delegation(..) | ast::ItemKind::DelegationMac(..) => {
|
||||||
// TODO: rewrite delegation items once syntax is established.
|
// TODO: rewrite delegation items once syntax is established.
|
||||||
// For now, leave the contents of the Span unformatted.
|
// For now, leave the contents of the Span unformatted.
|
||||||
self.push_rewrite(item.span, None)
|
self.push_rewrite(item.span, None)
|
||||||
|
|
|
@ -8,7 +8,6 @@ run-make/branch-protection-check-IBT/Makefile
|
||||||
run-make/c-dynamic-dylib/Makefile
|
run-make/c-dynamic-dylib/Makefile
|
||||||
run-make/c-dynamic-rlib/Makefile
|
run-make/c-dynamic-rlib/Makefile
|
||||||
run-make/c-link-to-rust-dylib/Makefile
|
run-make/c-link-to-rust-dylib/Makefile
|
||||||
run-make/c-link-to-rust-staticlib/Makefile
|
|
||||||
run-make/c-static-dylib/Makefile
|
run-make/c-static-dylib/Makefile
|
||||||
run-make/c-static-rlib/Makefile
|
run-make/c-static-rlib/Makefile
|
||||||
run-make/c-unwind-abi-catch-lib-panic/Makefile
|
run-make/c-unwind-abi-catch-lib-panic/Makefile
|
||||||
|
@ -94,8 +93,6 @@ run-make/invalid-staticlib/Makefile
|
||||||
run-make/issue-107094/Makefile
|
run-make/issue-107094/Makefile
|
||||||
run-make/issue-10971-temps-dir/Makefile
|
run-make/issue-10971-temps-dir/Makefile
|
||||||
run-make/issue-109934-lto-debuginfo/Makefile
|
run-make/issue-109934-lto-debuginfo/Makefile
|
||||||
run-make/issue-11908/Makefile
|
|
||||||
run-make/issue-14500/Makefile
|
|
||||||
run-make/issue-14698/Makefile
|
run-make/issue-14698/Makefile
|
||||||
run-make/issue-15460/Makefile
|
run-make/issue-15460/Makefile
|
||||||
run-make/issue-18943/Makefile
|
run-make/issue-18943/Makefile
|
||||||
|
@ -181,7 +178,6 @@ run-make/native-link-modifier-whole-archive/Makefile
|
||||||
run-make/no-alloc-shim/Makefile
|
run-make/no-alloc-shim/Makefile
|
||||||
run-make/no-builtins-attribute/Makefile
|
run-make/no-builtins-attribute/Makefile
|
||||||
run-make/no-builtins-lto/Makefile
|
run-make/no-builtins-lto/Makefile
|
||||||
run-make/no-cdylib-as-rdylib/Makefile
|
|
||||||
run-make/no-duplicate-libs/Makefile
|
run-make/no-duplicate-libs/Makefile
|
||||||
run-make/no-intermediate-extras/Makefile
|
run-make/no-intermediate-extras/Makefile
|
||||||
run-make/obey-crate-type-flag/Makefile
|
run-make/obey-crate-type-flag/Makefile
|
||||||
|
@ -194,7 +190,6 @@ run-make/output-with-hyphens/Makefile
|
||||||
run-make/override-aliased-flags/Makefile
|
run-make/override-aliased-flags/Makefile
|
||||||
run-make/overwrite-input/Makefile
|
run-make/overwrite-input/Makefile
|
||||||
run-make/panic-abort-eh_frame/Makefile
|
run-make/panic-abort-eh_frame/Makefile
|
||||||
run-make/panic-impl-transitive/Makefile
|
|
||||||
run-make/pass-linker-flags-flavor/Makefile
|
run-make/pass-linker-flags-flavor/Makefile
|
||||||
run-make/pass-linker-flags-from-dep/Makefile
|
run-make/pass-linker-flags-from-dep/Makefile
|
||||||
run-make/pass-linker-flags/Makefile
|
run-make/pass-linker-flags/Makefile
|
||||||
|
@ -247,9 +242,7 @@ run-make/rustdoc-scrape-examples-multiple/Makefile
|
||||||
run-make/rustdoc-scrape-examples-remap/Makefile
|
run-make/rustdoc-scrape-examples-remap/Makefile
|
||||||
run-make/rustdoc-scrape-examples-test/Makefile
|
run-make/rustdoc-scrape-examples-test/Makefile
|
||||||
run-make/rustdoc-scrape-examples-whitespace/Makefile
|
run-make/rustdoc-scrape-examples-whitespace/Makefile
|
||||||
run-make/rustdoc-themes/Makefile
|
|
||||||
run-make/rustdoc-verify-output-files/Makefile
|
run-make/rustdoc-verify-output-files/Makefile
|
||||||
run-make/rustdoc-with-out-dir-option/Makefile
|
|
||||||
run-make/rustdoc-with-output-option/Makefile
|
run-make/rustdoc-with-output-option/Makefile
|
||||||
run-make/rustdoc-with-short-out-dir-option/Makefile
|
run-make/rustdoc-with-short-out-dir-option/Makefile
|
||||||
run-make/sanitizer-cdylib-link/Makefile
|
run-make/sanitizer-cdylib-link/Makefile
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
# This test checks that C linking with Rust does not encounter any errors, with static libraries.
|
|
||||||
# See https://github.com/rust-lang/rust/issues/10434
|
|
||||||
|
|
||||||
# ignore-cross-compile
|
|
||||||
include ../tools.mk
|
|
||||||
|
|
||||||
# ignore-freebsd
|
|
||||||
# FIXME
|
|
||||||
|
|
||||||
all:
|
|
||||||
$(RUSTC) foo.rs
|
|
||||||
$(CC) bar.c $(call STATICLIB,foo) $(call OUT_EXE,bar) \
|
|
||||||
$(EXTRACFLAGS) $(EXTRACXXFLAGS)
|
|
||||||
$(call RUN,bar)
|
|
||||||
rm $(call STATICLIB,foo)
|
|
||||||
$(call RUN,bar)
|
|
15
tests/run-make/c-link-to-rust-staticlib/rmake.rs
Normal file
15
tests/run-make/c-link-to-rust-staticlib/rmake.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// This test checks that C linking with Rust does not encounter any errors, with a static library.
|
||||||
|
// See https://github.com/rust-lang/rust/issues/10434
|
||||||
|
|
||||||
|
//@ ignore-cross-compile
|
||||||
|
|
||||||
|
use run_make_support::{cc, extra_c_flags, run, rustc, static_lib};
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
rustc().input("foo.rs").run();
|
||||||
|
cc().input("bar.c").input(static_lib("foo")).out_exe("bar").args(&extra_c_flags()).run();
|
||||||
|
run("bar");
|
||||||
|
fs::remove_file(static_lib("foo"));
|
||||||
|
run("bar");
|
||||||
|
}
|
|
@ -26,8 +26,7 @@ fn main() {
|
||||||
.arg("--test")
|
.arg("--test")
|
||||||
.arg("--persist-doctests")
|
.arg("--persist-doctests")
|
||||||
.arg(out_dir)
|
.arg(out_dir)
|
||||||
.arg("--extern")
|
.extern_("t", extern_path)
|
||||||
.arg(format!("t={}", extern_path.display()))
|
|
||||||
.run();
|
.run();
|
||||||
check_generated_binaries();
|
check_generated_binaries();
|
||||||
});
|
});
|
||||||
|
@ -38,8 +37,7 @@ fn main() {
|
||||||
.arg("--test")
|
.arg("--test")
|
||||||
.arg("--persist-doctests")
|
.arg("--persist-doctests")
|
||||||
.arg(out_dir)
|
.arg(out_dir)
|
||||||
.arg("--extern")
|
.extern_("t", extern_path)
|
||||||
.arg(format!("t={}", extern_path.display()))
|
|
||||||
.arg("--no-run")
|
.arg("--no-run")
|
||||||
.run();
|
.run();
|
||||||
check_generated_binaries();
|
check_generated_binaries();
|
||||||
|
@ -59,8 +57,7 @@ fn main() {
|
||||||
.arg("doctests")
|
.arg("doctests")
|
||||||
.arg("--test-run-directory")
|
.arg("--test-run-directory")
|
||||||
.arg(run_dir)
|
.arg(run_dir)
|
||||||
.arg("--extern")
|
.extern_("t", "libt.rlib")
|
||||||
.arg("t=libt.rlib")
|
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
remove_dir_all(run_dir_path);
|
remove_dir_all(run_dir_path);
|
||||||
|
|
|
@ -29,8 +29,7 @@ fn main() {
|
||||||
.arg(run_dir_name)
|
.arg(run_dir_name)
|
||||||
.arg("--runtool")
|
.arg("--runtool")
|
||||||
.arg(&run_tool_binary)
|
.arg(&run_tool_binary)
|
||||||
.arg("--extern")
|
.extern_("t", "libt.rlib")
|
||||||
.arg("t=libt.rlib")
|
|
||||||
.current_dir(tmp_dir())
|
.current_dir(tmp_dir())
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
# ignore-cross-compile
|
|
||||||
# This test ensures that if you have the same rlib or dylib at two locations
|
|
||||||
# in the same path that you don't hit an assertion in the compiler.
|
|
||||||
#
|
|
||||||
# Note that this relies on `liburl` to be in the path somewhere else,
|
|
||||||
# and then our aux-built libraries will collide with liburl (they have
|
|
||||||
# the same version listed)
|
|
||||||
|
|
||||||
include ../tools.mk
|
|
||||||
|
|
||||||
all:
|
|
||||||
mkdir $(TMPDIR)/other
|
|
||||||
$(RUSTC) foo.rs --crate-type=dylib -C prefer-dynamic
|
|
||||||
mv $(call DYLIB,foo) $(TMPDIR)/other
|
|
||||||
$(RUSTC) foo.rs --crate-type=dylib -C prefer-dynamic
|
|
||||||
$(RUSTC) bar.rs -L $(TMPDIR)/other
|
|
||||||
rm -rf $(TMPDIR)
|
|
||||||
mkdir -p $(TMPDIR)/other
|
|
||||||
$(RUSTC) foo.rs --crate-type=rlib
|
|
||||||
mv $(TMPDIR)/libfoo.rlib $(TMPDIR)/other
|
|
||||||
$(RUSTC) foo.rs --crate-type=rlib
|
|
||||||
$(RUSTC) bar.rs -L $(TMPDIR)/other
|
|
|
@ -1,15 +0,0 @@
|
||||||
include ../tools.mk
|
|
||||||
|
|
||||||
# ignore-cross-compile
|
|
||||||
|
|
||||||
# Test to make sure that reachable extern fns are always available in final
|
|
||||||
# productcs, including when LTO is used. In this test, the `foo` crate has a
|
|
||||||
# reahable symbol, and is a dependency of the `bar` crate. When the `bar` crate
|
|
||||||
# is compiled with LTO, it shouldn't strip the symbol from `foo`, and that's the
|
|
||||||
# only way that `foo.c` will successfully compile.
|
|
||||||
|
|
||||||
all:
|
|
||||||
$(RUSTC) foo.rs --crate-type=rlib
|
|
||||||
$(RUSTC) bar.rs --crate-type=staticlib -C lto -L. -o $(TMPDIR)/libbar.a
|
|
||||||
$(CC) foo.c $(TMPDIR)/libbar.a $(EXTRACFLAGS) $(call OUT_EXE,foo)
|
|
||||||
$(call RUN,foo)
|
|
|
@ -1,16 +0,0 @@
|
||||||
# ignore-cross-compile
|
|
||||||
include ../tools.mk
|
|
||||||
|
|
||||||
# Test that rustc will not attempt to link against a cdylib as if
|
|
||||||
# it is a rust dylib when an rlib for the same crate is available.
|
|
||||||
# Previously rustc didn't actually check if any further formats of
|
|
||||||
# a crate which has been loaded are of the same version and if
|
|
||||||
# they are actually valid. This caused a cdylib to be interpreted
|
|
||||||
# as rust dylib as soon as the corresponding rlib was loaded. As
|
|
||||||
# cdylibs don't export any rust symbols, linking would fail if
|
|
||||||
# rustc decides to link against the cdylib rather than the rlib.
|
|
||||||
|
|
||||||
all:
|
|
||||||
$(RUSTC) bar.rs --crate-type=rlib --crate-type=cdylib
|
|
||||||
$(RUSTC) foo.rs -C prefer-dynamic
|
|
||||||
$(call RUN,foo)
|
|
16
tests/run-make/no-cdylib-as-rdylib/rmake.rs
Normal file
16
tests/run-make/no-cdylib-as-rdylib/rmake.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// This test produces an rlib and a cdylib from bar.rs.
|
||||||
|
// Then, foo.rs attempts to link to the bar library.
|
||||||
|
// If the test passes, that means rustc favored the rlib and ignored the cdylib.
|
||||||
|
// If the test fails, that is because the cdylib was picked, which does not export
|
||||||
|
// any Rust symbols.
|
||||||
|
// See https://github.com/rust-lang/rust/pull/113695
|
||||||
|
|
||||||
|
//@ ignore-cross-compile
|
||||||
|
|
||||||
|
use run_make_support::{run, rustc};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
rustc().input("bar.rs").crate_type("rlib").crate_type("cdylib").run();
|
||||||
|
rustc().input("foo.rs").arg("-Cprefer-dynamic").run();
|
||||||
|
run("foo");
|
||||||
|
}
|
|
@ -1,7 +0,0 @@
|
||||||
include ../tools.mk
|
|
||||||
|
|
||||||
# NOTE we use --emit=llvm-ir to avoid running the linker (linking will fail because there's no main
|
|
||||||
# in this crate)
|
|
||||||
all:
|
|
||||||
$(RUSTC) panic-impl-provider.rs
|
|
||||||
$(RUSTC) panic-impl-consumer.rs -C panic=abort --emit=llvm-ir -L $(TMPDIR)
|
|
19
tests/run-make/panic-impl-transitive/rmake.rs
Normal file
19
tests/run-make/panic-impl-transitive/rmake.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// In Rust programs where the standard library is unavailable (#![no_std]), we may be interested
|
||||||
|
// in customizing how panics are handled. Here, the provider specifies that panics should be handled
|
||||||
|
// by entering an infinite loop. This test checks that this panic implementation can be transitively
|
||||||
|
// provided by an external crate.
|
||||||
|
// --emit=llvm-ir is used to avoid running the linker, as linking will fail due to the lack of main
|
||||||
|
// function in the crate.
|
||||||
|
// See https://github.com/rust-lang/rust/pull/50338
|
||||||
|
|
||||||
|
use run_make_support::{rustc, tmp_dir};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
rustc().input("panic-impl-provider.rs").run();
|
||||||
|
rustc()
|
||||||
|
.input("panic-impl-consumer.rs")
|
||||||
|
.panic("abort")
|
||||||
|
.emit("llvm-ir")
|
||||||
|
.library_search_path(tmp_dir())
|
||||||
|
.run();
|
||||||
|
}
|
26
tests/run-make/reachable-extern-fn-available-lto/rmake.rs
Normal file
26
tests/run-make/reachable-extern-fn-available-lto/rmake.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// Test to make sure that reachable extern fns are always available in final
|
||||||
|
// productcs, including when link time optimizations (LTO) are used.
|
||||||
|
|
||||||
|
// In this test, the `foo` crate has a reahable symbol,
|
||||||
|
// and is a dependency of the `bar` crate. When the `bar` crate
|
||||||
|
// is compiled with LTO, it shouldn't strip the symbol from `foo`, and that's the
|
||||||
|
// only way that `foo.c` will successfully compile.
|
||||||
|
// See https://github.com/rust-lang/rust/issues/14500
|
||||||
|
|
||||||
|
//@ ignore-cross-compile
|
||||||
|
|
||||||
|
use run_make_support::{cc, extra_c_flags, run, rustc, static_lib};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let libbar_path = static_lib("bar");
|
||||||
|
rustc().input("foo.rs").crate_type("rlib").run();
|
||||||
|
rustc()
|
||||||
|
.input("bar.rs")
|
||||||
|
.crate_type("staticlib")
|
||||||
|
.arg("-Clto")
|
||||||
|
.library_search_path(".")
|
||||||
|
.output(&libbar_path)
|
||||||
|
.run();
|
||||||
|
cc().input("foo.c").input(libbar_path).args(&extra_c_flags()).out_exe("foo").run();
|
||||||
|
run("foo");
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
use run_make_support::{rustdoc, tmp_dir};
|
use run_make_support::{python_command, rustdoc, tmp_dir};
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let out_dir = tmp_dir().join("out");
|
let out_dir = tmp_dir().join("out");
|
||||||
|
@ -10,6 +9,5 @@ fn main() {
|
||||||
.output(&out_dir)
|
.output(&out_dir)
|
||||||
.run();
|
.run();
|
||||||
// FIXME (GuillaumeGomez): Port the python script to Rust as well.
|
// FIXME (GuillaumeGomez): Port the python script to Rust as well.
|
||||||
let python = std::env::var("PYTHON").unwrap_or("python".into());
|
assert!(python_command().arg("validate_json.py").arg(&out_dir).status().unwrap().success());
|
||||||
assert!(Command::new(python).arg("validate_json.py").arg(&out_dir).status().unwrap().success());
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use run_make_support::{python_command, rustc, rustdoc, source_path, tmp_dir};
|
use run_make_support::{htmldocck, rustc, rustdoc, source_path, tmp_dir};
|
||||||
use std::fs::read_dir;
|
use std::fs::read_dir;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
@ -45,11 +45,5 @@ fn main() {
|
||||||
}
|
}
|
||||||
rustdoc.run();
|
rustdoc.run();
|
||||||
|
|
||||||
python_command()
|
assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success());
|
||||||
.arg(source_path().join("/src/etc/htmldocck.py"))
|
|
||||||
.arg(out_dir)
|
|
||||||
.arg("src/lib.rs")
|
|
||||||
.status()
|
|
||||||
.unwrap()
|
|
||||||
.success();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
include ../tools.mk
|
|
||||||
|
|
||||||
# Test that rustdoc will properly load in a theme file and display it in the theme selector.
|
|
||||||
|
|
||||||
OUTPUT_DIR := "$(TMPDIR)/rustdoc-themes"
|
|
||||||
|
|
||||||
all:
|
|
||||||
awk '/Begin theme: light/ {in_theme=1;next} /End theme:/ {in_theme=0} { if (in_theme) print }' \
|
|
||||||
< '$(S)/src/librustdoc/html/static/css/noscript.css' > '$(TMPDIR)/test.css'
|
|
||||||
$(RUSTDOC) -o $(OUTPUT_DIR) foo.rs --theme $(TMPDIR)/test.css
|
|
||||||
$(HTMLDOCCK) $(OUTPUT_DIR) foo.rs
|
|
31
tests/run-make/rustdoc-themes/rmake.rs
Normal file
31
tests/run-make/rustdoc-themes/rmake.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// Test that rustdoc will properly load in a theme file and display it in the theme selector.
|
||||||
|
|
||||||
|
use run_make_support::{htmldocck, rustdoc, source_path, tmp_dir};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let out_dir = tmp_dir().join("rustdoc-themes");
|
||||||
|
let test_css = out_dir.join("test.css");
|
||||||
|
|
||||||
|
let no_script =
|
||||||
|
std::fs::read_to_string(source_path().join("src/librustdoc/html/static/css/noscript.css"))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut test_content = String::new();
|
||||||
|
let mut found_begin_light = false;
|
||||||
|
for line in no_script.split('\n') {
|
||||||
|
if line == "/* Begin theme: light */" {
|
||||||
|
found_begin_light = true;
|
||||||
|
} else if line == "/* End theme: light */" {
|
||||||
|
break;
|
||||||
|
} else if found_begin_light {
|
||||||
|
test_content.push_str(line);
|
||||||
|
test_content.push('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert!(!test_content.is_empty());
|
||||||
|
std::fs::create_dir_all(&out_dir).unwrap();
|
||||||
|
std::fs::write(&test_css, test_content).unwrap();
|
||||||
|
|
||||||
|
rustdoc().output(&out_dir).input("foo.rs").arg("--theme").arg(&test_css).run();
|
||||||
|
assert!(htmldocck().arg(out_dir).arg("foo.rs").status().unwrap().success());
|
||||||
|
}
|
|
@ -1,8 +0,0 @@
|
||||||
include ../tools.mk
|
|
||||||
|
|
||||||
OUTPUT_DIR := "$(TMPDIR)/rustdoc"
|
|
||||||
|
|
||||||
all:
|
|
||||||
$(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR)
|
|
||||||
|
|
||||||
$(HTMLDOCCK) $(OUTPUT_DIR) src/lib.rs
|
|
7
tests/run-make/rustdoc-with-out-dir-option/rmake.rs
Normal file
7
tests/run-make/rustdoc-with-out-dir-option/rmake.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
use run_make_support::{htmldocck, rustdoc, tmp_dir};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let out_dir = tmp_dir().join("rustdoc");
|
||||||
|
rustdoc().input("src/lib.rs").crate_name("foobar").crate_type("lib").output(&out_dir).run();
|
||||||
|
assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success());
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue