Merge from rustc
This commit is contained in:
commit
7d12e50f73
1778 changed files with 31621 additions and 19057 deletions
|
|
@ -161,6 +161,7 @@ static TARGETS: &[&str] = &[
|
|||
"wasm32-wasip1",
|
||||
"wasm32-wasip1-threads",
|
||||
"wasm32-wasip2",
|
||||
"wasm32v1-none",
|
||||
"x86_64-apple-darwin",
|
||||
"x86_64-apple-ios",
|
||||
"x86_64-apple-ios-macabi",
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit cf53cc54bb593b5ec3dc2be4b1702f50c36d24d5
|
||||
Subproject commit e75214ea4936d2f2c909a71a1237042cc0e14b07
|
||||
|
|
@ -31,6 +31,7 @@ declare_clippy_lint! {
|
|||
pub COGNITIVE_COMPLEXITY,
|
||||
nursery,
|
||||
"functions that should be split up into multiple functions"
|
||||
@eval_always = true
|
||||
}
|
||||
|
||||
pub struct CognitiveComplexity {
|
||||
|
|
|
|||
40
src/tools/clippy/clippy_lints/src/ctfe.rs
Normal file
40
src/tools/clippy/clippy_lints/src/ctfe.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{Body, FnDecl};
|
||||
use rustc_lint::Level::Deny;
|
||||
use rustc_lint::{LateContext, LateLintPass, Lint};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::Span;
|
||||
|
||||
/// Ensures that Constant-time Function Evaluation is being done (specifically, MIR lint passes).
|
||||
/// As Clippy deactivates codegen, this lint ensures that CTFE (used in hard errors) is still ran.
|
||||
pub static CLIPPY_CTFE: &Lint = &Lint {
|
||||
name: &"clippy::CLIPPY_CTFE",
|
||||
default_level: Deny,
|
||||
desc: "Ensure CTFE is being made",
|
||||
edition_lint_opts: None,
|
||||
report_in_external_macro: true,
|
||||
future_incompatible: None,
|
||||
is_externally_loaded: true,
|
||||
crate_level_only: false,
|
||||
eval_always: true,
|
||||
..Lint::default_fields_for_macro()
|
||||
};
|
||||
|
||||
// No static CLIPPY_CTFE_INFO because we want this lint to be invisible
|
||||
|
||||
declare_lint_pass! { ClippyCtfe => [CLIPPY_CTFE] }
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for ClippyCtfe {
|
||||
fn check_fn(
|
||||
&mut self,
|
||||
cx: &LateContext<'_>,
|
||||
_: FnKind<'tcx>,
|
||||
_: &'tcx FnDecl<'tcx>,
|
||||
_: &'tcx Body<'tcx>,
|
||||
_: Span,
|
||||
defid: LocalDefId,
|
||||
) {
|
||||
cx.tcx.ensure().mir_drops_elaborated_and_const_checked(defid); // Lint
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ macro_rules! declare_clippy_lint {
|
|||
$desc:literal,
|
||||
$version_expr:expr,
|
||||
$version_lit:literal
|
||||
$(, $eval_always: literal)?
|
||||
) => {
|
||||
rustc_session::declare_tool_lint! {
|
||||
$(#[doc = $lit])*
|
||||
|
|
@ -17,6 +18,7 @@ macro_rules! declare_clippy_lint {
|
|||
$category,
|
||||
$desc,
|
||||
report_in_external_macro:true
|
||||
$(, @eval_always = $eval_always)?
|
||||
}
|
||||
|
||||
pub(crate) static ${concat($lint_name, _INFO)}: &'static crate::LintInfo = &crate::LintInfo {
|
||||
|
|
@ -33,11 +35,12 @@ macro_rules! declare_clippy_lint {
|
|||
pub $lint_name:ident,
|
||||
restriction,
|
||||
$desc:literal
|
||||
$(@eval_always = $eval_always: literal)?
|
||||
) => {
|
||||
declare_clippy_lint! {@
|
||||
$(#[doc = $lit])*
|
||||
pub $lint_name, Allow, crate::LintCategory::Restriction, $desc,
|
||||
Some($version), $version
|
||||
Some($version), $version $(, $eval_always)?
|
||||
}
|
||||
};
|
||||
(
|
||||
|
|
@ -46,12 +49,12 @@ macro_rules! declare_clippy_lint {
|
|||
pub $lint_name:ident,
|
||||
style,
|
||||
$desc:literal
|
||||
$(@eval_always = $eval_always: literal)?
|
||||
) => {
|
||||
declare_clippy_lint! {@
|
||||
$(#[doc = $lit])*
|
||||
pub $lint_name, Warn, crate::LintCategory::Style, $desc,
|
||||
Some($version), $version
|
||||
|
||||
Some($version), $version $(, $eval_always)?
|
||||
}
|
||||
};
|
||||
(
|
||||
|
|
@ -60,11 +63,12 @@ macro_rules! declare_clippy_lint {
|
|||
pub $lint_name:ident,
|
||||
correctness,
|
||||
$desc:literal
|
||||
$(@eval_always = $eval_always: literal)?
|
||||
) => {
|
||||
declare_clippy_lint! {@
|
||||
$(#[doc = $lit])*
|
||||
pub $lint_name, Deny, crate::LintCategory::Correctness, $desc,
|
||||
Some($version), $version
|
||||
Some($version), $version $(, $eval_always)?
|
||||
|
||||
}
|
||||
};
|
||||
|
|
@ -74,11 +78,12 @@ macro_rules! declare_clippy_lint {
|
|||
pub $lint_name:ident,
|
||||
perf,
|
||||
$desc:literal
|
||||
$(@eval_always = $eval_always: literal)?
|
||||
) => {
|
||||
declare_clippy_lint! {@
|
||||
$(#[doc = $lit])*
|
||||
pub $lint_name, Warn, crate::LintCategory::Perf, $desc,
|
||||
Some($version), $version
|
||||
Some($version), $version $(, $eval_always)?
|
||||
}
|
||||
};
|
||||
(
|
||||
|
|
@ -87,11 +92,12 @@ macro_rules! declare_clippy_lint {
|
|||
pub $lint_name:ident,
|
||||
complexity,
|
||||
$desc:literal
|
||||
$(@eval_always = $eval_always: literal)?
|
||||
) => {
|
||||
declare_clippy_lint! {@
|
||||
$(#[doc = $lit])*
|
||||
pub $lint_name, Warn, crate::LintCategory::Complexity, $desc,
|
||||
Some($version), $version
|
||||
Some($version), $version $(, $eval_always)?
|
||||
}
|
||||
};
|
||||
(
|
||||
|
|
@ -100,11 +106,12 @@ macro_rules! declare_clippy_lint {
|
|||
pub $lint_name:ident,
|
||||
suspicious,
|
||||
$desc:literal
|
||||
$(@eval_always = $eval_always: literal)?
|
||||
) => {
|
||||
declare_clippy_lint! {@
|
||||
$(#[doc = $lit])*
|
||||
pub $lint_name, Warn, crate::LintCategory::Suspicious, $desc,
|
||||
Some($version), $version
|
||||
Some($version), $version $(, $eval_always)?
|
||||
}
|
||||
};
|
||||
(
|
||||
|
|
@ -113,11 +120,12 @@ macro_rules! declare_clippy_lint {
|
|||
pub $lint_name:ident,
|
||||
nursery,
|
||||
$desc:literal
|
||||
$(@eval_always = $eval_always: literal)?
|
||||
) => {
|
||||
declare_clippy_lint! {@
|
||||
$(#[doc = $lit])*
|
||||
pub $lint_name, Allow, crate::LintCategory::Nursery, $desc,
|
||||
Some($version), $version
|
||||
Some($version), $version $(, $eval_always)?
|
||||
}
|
||||
};
|
||||
(
|
||||
|
|
@ -126,11 +134,12 @@ macro_rules! declare_clippy_lint {
|
|||
pub $lint_name:ident,
|
||||
pedantic,
|
||||
$desc:literal
|
||||
$(@eval_always = $eval_always: literal)?
|
||||
) => {
|
||||
declare_clippy_lint! {@
|
||||
$(#[doc = $lit])*
|
||||
pub $lint_name, Allow, crate::LintCategory::Pedantic, $desc,
|
||||
Some($version), $version
|
||||
Some($version), $version $(, $eval_always)?
|
||||
}
|
||||
};
|
||||
(
|
||||
|
|
@ -139,11 +148,12 @@ macro_rules! declare_clippy_lint {
|
|||
pub $lint_name:ident,
|
||||
cargo,
|
||||
$desc:literal
|
||||
$(@eval_always = $eval_always: literal)?
|
||||
) => {
|
||||
declare_clippy_lint! {@
|
||||
$(#[doc = $lit])*
|
||||
pub $lint_name, Allow, crate::LintCategory::Cargo, $desc,
|
||||
Some($version), $version
|
||||
Some($version), $version $(, $eval_always)?
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ declare_with_version! { RENAMED(RENAMED_VERSION): &[(&str, &str)] = &[
|
|||
#[clippy::version = ""]
|
||||
("clippy::positional_named_format_parameters", "named_arguments_used_positionally"),
|
||||
#[clippy::version = ""]
|
||||
("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr"),
|
||||
("clippy::temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"),
|
||||
#[clippy::version = ""]
|
||||
("clippy::undropped_manually_drops", "undropped_manually_drops"),
|
||||
#[clippy::version = ""]
|
||||
|
|
|
|||
|
|
@ -324,7 +324,7 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h
|
|||
// If the current self type doesn't implement Copy (due to generic constraints), search to see if
|
||||
// there's a Copy impl for any instance of the adt.
|
||||
if !is_copy(cx, ty) {
|
||||
if ty_subs.non_erasable_generics(cx.tcx, ty_adt.did()).next().is_some() {
|
||||
if ty_subs.non_erasable_generics().next().is_some() {
|
||||
let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(©_id).map_or(false, |impls| {
|
||||
impls.iter().any(|&id| {
|
||||
matches!(cx.tcx.type_of(id).instantiate_identity().kind(), ty::Adt(adt, _)
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ impl LateLintPass<'_> for EmptyEnum {
|
|||
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
|
||||
if let ItemKind::Enum(..) = item.kind
|
||||
// Only suggest the `never_type` if the feature is enabled
|
||||
&& cx.tcx.features().never_type
|
||||
&& cx.tcx.features().never_type()
|
||||
&& let Some(adt) = cx.tcx.type_of(item.owner_id).instantiate_identity().ty_adt_def()
|
||||
&& adt.variants().is_empty()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use clippy_utils::source::snippet;
|
|||
use rustc_errors::{Applicability, SuggestionStyle};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{
|
||||
AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifier, TyKind,
|
||||
AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifiers, TyKind,
|
||||
WherePredicate,
|
||||
};
|
||||
use rustc_hir_analysis::lower_ty;
|
||||
|
|
@ -234,7 +234,7 @@ fn collect_supertrait_bounds<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds
|
|||
.iter()
|
||||
.filter_map(|bound| {
|
||||
if let GenericBound::Trait(poly_trait) = bound
|
||||
&& let TraitBoundModifier::None = poly_trait.modifiers
|
||||
&& let TraitBoundModifiers::NONE = poly_trait.modifiers
|
||||
&& let [.., path] = poly_trait.trait_ref.path.segments
|
||||
&& poly_trait.bound_generic_params.is_empty()
|
||||
&& let Some(trait_def_id) = path.res.opt_def_id()
|
||||
|
|
@ -300,7 +300,7 @@ fn check<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds<'tcx>) {
|
|||
// simply comparing trait `DefId`s won't be enough. We also need to compare the generics.
|
||||
for (index, bound) in bounds.iter().enumerate() {
|
||||
if let GenericBound::Trait(poly_trait) = bound
|
||||
&& let TraitBoundModifier::None = poly_trait.modifiers
|
||||
&& let TraitBoundModifiers::NONE = poly_trait.modifiers
|
||||
&& let [.., path] = poly_trait.trait_ref.path.segments
|
||||
&& let implied_args = path.args.map_or([].as_slice(), |a| a.args)
|
||||
&& let implied_constraints = path.args.map_or([].as_slice(), |a| a.constraints)
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ extern crate clippy_utils;
|
|||
#[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
|
||||
mod utils;
|
||||
|
||||
pub mod ctfe; // Very important lint, do not remove (rust#125116)
|
||||
pub mod declared_lints;
|
||||
pub mod deprecated_lints;
|
||||
|
||||
|
|
@ -605,6 +606,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
|||
});
|
||||
}
|
||||
|
||||
store.register_late_pass(|_| Box::new(ctfe::ClippyCtfe));
|
||||
|
||||
store.register_late_pass(move |_| Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir));
|
||||
store.register_late_pass(|_| Box::new(utils::author::Author));
|
||||
|
|
|
|||
|
|
@ -111,11 +111,7 @@ fn check_int_ty_and_feature(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
|||
let expr_ty = cx.typeck_results().expr_ty(expr);
|
||||
match expr_ty.peel_refs().kind() {
|
||||
ty::Uint(_) => true,
|
||||
ty::Int(_) => cx
|
||||
.tcx
|
||||
.features()
|
||||
.declared_features
|
||||
.contains(&Symbol::intern("int_roundings")),
|
||||
ty::Int(_) => cx.tcx.features().enabled(Symbol::intern("int_roundings")),
|
||||
|
||||
_ => false,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
|
|||
let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect();
|
||||
for (&(i, arm1), &(j, arm2)) in search_same(&indexed_arms, hash, eq) {
|
||||
if matches!(arm2.pat.kind, PatKind::Wild) {
|
||||
if !cx.tcx.features().non_exhaustive_omitted_patterns_lint
|
||||
if !cx.tcx.features().non_exhaustive_omitted_patterns_lint()
|
||||
|| is_lint_allowed(cx, NON_EXHAUSTIVE_OMITTED_PATTERNS, arm2.hir_id)
|
||||
{
|
||||
let arm_span = adjusted_arm_span(cx, arm1.span);
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ fn emit_redundant_guards<'tcx>(
|
|||
fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
for_each_expr_without_closures(expr, |expr| {
|
||||
if match expr.kind {
|
||||
ExprKind::ConstBlock(..) => cx.tcx.features().inline_const_pat,
|
||||
ExprKind::ConstBlock(..) => cx.tcx.features().inline_const_pat(),
|
||||
ExprKind::Call(c, ..) if let ExprKind::Path(qpath) = c.kind => {
|
||||
// Allow ctors
|
||||
matches!(cx.qpath_res(&qpath, c.hir_id), Res::Def(DefKind::Ctor(..), ..))
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def_id::{DefId, DefIdMap};
|
||||
use rustc_hir::{GenericBound, Generics, PolyTraitRef, TraitBoundModifier, WherePredicate};
|
||||
use rustc_hir::{GenericBound, Generics, PolyTraitRef, TraitBoundModifiers, BoundPolarity, WherePredicate};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::{ClauseKind, PredicatePolarity};
|
||||
use rustc_session::declare_lint_pass;
|
||||
|
|
@ -118,13 +118,13 @@ impl LateLintPass<'_> for NeedlessMaybeSized {
|
|||
let maybe_sized_params: DefIdMap<_> = type_param_bounds(generics)
|
||||
.filter(|bound| {
|
||||
bound.trait_bound.trait_ref.trait_def_id() == Some(sized_trait)
|
||||
&& bound.trait_bound.modifiers == TraitBoundModifier::Maybe
|
||||
&& matches!(bound.trait_bound.modifiers.polarity, BoundPolarity::Maybe(_))
|
||||
})
|
||||
.map(|bound| (bound.param, bound))
|
||||
.collect();
|
||||
|
||||
for bound in type_param_bounds(generics) {
|
||||
if bound.trait_bound.modifiers == TraitBoundModifier::None
|
||||
if bound.trait_bound.modifiers == TraitBoundModifiers::NONE
|
||||
&& let Some(sized_bound) = maybe_sized_params.get(&bound.param)
|
||||
&& let Some(path) = path_to_sized_bound(cx, bound.trait_bound)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use rustc_errors::Applicability;
|
|||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{
|
||||
GenericBound, Generics, Item, ItemKind, LangItem, Node, Path, PathSegment, PredicateOrigin, QPath,
|
||||
TraitBoundModifier, TraitItem, TraitRef, Ty, TyKind, WherePredicate,
|
||||
TraitBoundModifiers, TraitItem, TraitRef, Ty, TyKind, WherePredicate, BoundPolarity,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::impl_lint_pass;
|
||||
|
|
@ -233,7 +233,7 @@ impl TraitBounds {
|
|||
fn cannot_combine_maybe_bound(&self, cx: &LateContext<'_>, bound: &GenericBound<'_>) -> bool {
|
||||
if !self.msrv.meets(msrvs::MAYBE_BOUND_IN_WHERE)
|
||||
&& let GenericBound::Trait(tr) = bound
|
||||
&& let TraitBoundModifier::Maybe = tr.modifiers
|
||||
&& let BoundPolarity::Maybe(_) = tr.modifiers.polarity
|
||||
{
|
||||
cx.tcx.lang_items().get(LangItem::Sized) == tr.trait_ref.path.res.opt_def_id()
|
||||
} else {
|
||||
|
|
@ -374,12 +374,12 @@ fn check_trait_bound_duplication<'tcx>(cx: &LateContext<'tcx>, generics: &'_ Gen
|
|||
struct ComparableTraitRef<'a, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
trait_ref: &'tcx TraitRef<'tcx>,
|
||||
modifier: TraitBoundModifier,
|
||||
modifiers: TraitBoundModifiers,
|
||||
}
|
||||
|
||||
impl PartialEq for ComparableTraitRef<'_, '_> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.modifier == other.modifier
|
||||
SpanlessEq::new(self.cx).eq_modifiers(self.modifiers, other.modifiers)
|
||||
&& SpanlessEq::new(self.cx)
|
||||
.paths_by_resolution()
|
||||
.eq_path(self.trait_ref.path, other.trait_ref.path)
|
||||
|
|
@ -390,8 +390,8 @@ impl Hash for ComparableTraitRef<'_, '_> {
|
|||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
let mut s = SpanlessHash::new(self.cx).paths_by_resolution();
|
||||
s.hash_path(self.trait_ref.path);
|
||||
s.hash_modifiers(self.modifiers);
|
||||
state.write_u64(s.finish());
|
||||
self.modifier.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -400,7 +400,7 @@ fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'
|
|||
let trait_path = t.trait_ref.path;
|
||||
let trait_span = {
|
||||
let path_span = trait_path.span;
|
||||
if let TraitBoundModifier::Maybe = t.modifiers {
|
||||
if let BoundPolarity::Maybe(_) = t.modifiers.polarity {
|
||||
path_span.with_lo(path_span.lo() - BytePos(1)) // include the `?`
|
||||
} else {
|
||||
path_span
|
||||
|
|
@ -427,7 +427,7 @@ fn rollup_traits<'cx, 'tcx>(
|
|||
ComparableTraitRef {
|
||||
cx,
|
||||
trait_ref: &t.trait_ref,
|
||||
modifier: t.modifiers,
|
||||
modifiers: t.modifiers,
|
||||
},
|
||||
t.span,
|
||||
))
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ impl From<&Attribute> for IdentIter {
|
|||
struct IdentCollector(Vec<Ident>);
|
||||
|
||||
impl Visitor<'_> for IdentCollector {
|
||||
fn visit_ident(&mut self, ident: Ident) {
|
||||
self.0.push(ident);
|
||||
fn visit_ident(&mut self, ident: &Ident) {
|
||||
self.0.push(*ident);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ use rustc_hir::def::{DefKind, Res};
|
|||
use rustc_hir::{
|
||||
ArrayLen, AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr,
|
||||
ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime,
|
||||
LifetimeName, Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind,
|
||||
LifetimeName, Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitBoundModifiers, Ty,
|
||||
TyKind,
|
||||
};
|
||||
use rustc_lexer::{TokenKind, tokenize};
|
||||
use rustc_lint::LateContext;
|
||||
|
|
@ -126,6 +127,11 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
|||
pub fn eq_path_segments(&mut self, left: &[PathSegment<'_>], right: &[PathSegment<'_>]) -> bool {
|
||||
self.inter_expr().eq_path_segments(left, right)
|
||||
}
|
||||
|
||||
pub fn eq_modifiers(&mut self, left: TraitBoundModifiers, right: TraitBoundModifiers) -> bool {
|
||||
std::mem::discriminant(&left.constness) == std::mem::discriminant(&right.constness)
|
||||
&& std::mem::discriminant(&left.polarity) == std::mem::discriminant(&right.polarity)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct HirEqInterExpr<'a, 'b, 'tcx> {
|
||||
|
|
@ -1143,6 +1149,12 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn hash_modifiers(&mut self, modifiers: TraitBoundModifiers) {
|
||||
let TraitBoundModifiers { constness, polarity } = modifiers;
|
||||
std::mem::discriminant(&polarity).hash(&mut self.s);
|
||||
std::mem::discriminant(&constness).hash(&mut self.s);
|
||||
}
|
||||
|
||||
pub fn hash_stmt(&mut self, b: &Stmt<'_>) {
|
||||
std::mem::discriminant(&b.kind).hash(&mut self.s);
|
||||
|
||||
|
|
|
|||
|
|
@ -334,7 +334,7 @@ fn check_terminator<'tcx>(
|
|||
| TerminatorKind::TailCall { func, args, fn_span: _ } => {
|
||||
let fn_ty = func.ty(body, tcx);
|
||||
if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() {
|
||||
if !is_const_fn(tcx, fn_def_id, msrv) {
|
||||
if !is_stable_const_fn(tcx, fn_def_id, msrv) {
|
||||
return Err((
|
||||
span,
|
||||
format!(
|
||||
|
|
@ -377,12 +377,12 @@ fn check_terminator<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool {
|
||||
fn is_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool {
|
||||
tcx.is_const_fn(def_id)
|
||||
&& tcx.lookup_const_stability(def_id).map_or(true, |const_stab| {
|
||||
&& tcx.lookup_const_stability(def_id).is_none_or(|const_stab| {
|
||||
if let rustc_attr::StabilityLevel::Stable { since, .. } = const_stab.level {
|
||||
// Checking MSRV is manually necessary because `rustc` has no such concept. This entire
|
||||
// function could be removed if `rustc` provided a MSRV-aware version of `is_const_fn`.
|
||||
// function could be removed if `rustc` provided a MSRV-aware version of `is_stable_const_fn`.
|
||||
// as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262.
|
||||
|
||||
let const_stab_rust_version = match since {
|
||||
|
|
@ -393,8 +393,12 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool {
|
|||
|
||||
msrv.meets(const_stab_rust_version)
|
||||
} else {
|
||||
// Unstable const fn with the feature enabled.
|
||||
msrv.current().is_none()
|
||||
// Unstable const fn, check if the feature is enabled. We need both the regular stability
|
||||
// feature and (if set) the const stability feature to const-call this function.
|
||||
let stab = tcx.lookup_stability(def_id);
|
||||
let is_enabled = stab.is_some_and(|s| s.is_stable() || tcx.features().enabled(s.feature))
|
||||
&& const_stab.feature.is_none_or(|f| tcx.features().enabled(f));
|
||||
is_enabled && msrv.current().is_none()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -207,16 +207,7 @@ fn path_segment_certainty(
|
|||
if cx.tcx.res_generics_def_id(path_segment.res).is_some() {
|
||||
let generics = cx.tcx.generics_of(def_id);
|
||||
|
||||
let own_count = generics.own_params.len()
|
||||
- usize::from(generics.host_effect_index.is_some_and(|index| {
|
||||
// Check that the host index actually belongs to this resolution.
|
||||
// E.g. for `Add::add`, host_effect_index is `Some(2)`, but it's part of the parent `Add`
|
||||
// trait's generics.
|
||||
// Add params: [Self#0, Rhs#1, host#2] parent_count=0, count=3
|
||||
// Add::add params: [] parent_count=3, count=3
|
||||
// (3..3).contains(&host_effect_index) => false
|
||||
(generics.parent_count..generics.count()).contains(&index)
|
||||
}));
|
||||
let own_count = generics.own_params.len();
|
||||
let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && own_count == 0 {
|
||||
Certainty::Certain(None)
|
||||
} else {
|
||||
|
|
@ -310,8 +301,7 @@ fn type_is_inferable_from_arguments(cx: &LateContext<'_>, expr: &Expr<'_>) -> bo
|
|||
|
||||
// Check that all type parameters appear in the functions input types.
|
||||
(0..(generics.parent_count + generics.own_params.len()) as u32).all(|index| {
|
||||
Some(index as usize) == generics.host_effect_index
|
||||
|| fn_sig
|
||||
fn_sig
|
||||
.inputs()
|
||||
.iter()
|
||||
.any(|input_ty| contains_param(*input_ty.skip_binder(), index))
|
||||
|
|
|
|||
|
|
@ -346,13 +346,13 @@ pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) ->
|
|||
.cx
|
||||
.qpath_res(p, hir_id)
|
||||
.opt_def_id()
|
||||
.map_or(false, |id| self.cx.tcx.is_const_fn_raw(id)) => {},
|
||||
.map_or(false, |id| self.cx.tcx.is_const_fn(id)) => {},
|
||||
ExprKind::MethodCall(..)
|
||||
if self
|
||||
.cx
|
||||
.typeck_results()
|
||||
.type_dependent_def_id(e.hir_id)
|
||||
.map_or(false, |id| self.cx.tcx.is_const_fn_raw(id)) => {},
|
||||
.map_or(false, |id| self.cx.tcx.is_const_fn(id)) => {},
|
||||
ExprKind::Binary(_, lhs, rhs)
|
||||
if self.cx.typeck_results().expr_ty(lhs).peel_refs().is_primitive_ty()
|
||||
&& self.cx.typeck_results().expr_ty(rhs).peel_refs().is_primitive_ty() => {},
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#![warn(clippy::author)]
|
||||
|
||||
fn main() {
|
||||
#[clippy::author]
|
||||
let x: char = 0x45 as char;
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
//@no-rustfix
|
||||
|
||||
#![feature(repr128)]
|
||||
#![feature(isqrt)]
|
||||
#![allow(incomplete_features)]
|
||||
#![warn(
|
||||
clippy::cast_precision_loss,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
|
||||
--> tests/ui/cast.rs:26:5
|
||||
--> tests/ui/cast.rs:25:5
|
||||
|
|
||||
LL | x0 as f32;
|
||||
| ^^^^^^^^^
|
||||
|
|
@ -8,37 +8,37 @@ LL | x0 as f32;
|
|||
= help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]`
|
||||
|
||||
error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
|
||||
--> tests/ui/cast.rs:30:5
|
||||
--> tests/ui/cast.rs:29:5
|
||||
|
|
||||
LL | x1 as f32;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
|
||||
--> tests/ui/cast.rs:32:5
|
||||
--> tests/ui/cast.rs:31:5
|
||||
|
|
||||
LL | x1 as f64;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
|
||||
--> tests/ui/cast.rs:35:5
|
||||
--> tests/ui/cast.rs:34:5
|
||||
|
|
||||
LL | x2 as f32;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
|
||||
--> tests/ui/cast.rs:38:5
|
||||
--> tests/ui/cast.rs:37:5
|
||||
|
|
||||
LL | x3 as f32;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
|
||||
--> tests/ui/cast.rs:40:5
|
||||
--> tests/ui/cast.rs:39:5
|
||||
|
|
||||
LL | x3 as f64;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: casting `f32` to `i32` may truncate the value
|
||||
--> tests/ui/cast.rs:43:5
|
||||
--> tests/ui/cast.rs:42:5
|
||||
|
|
||||
LL | 1f32 as i32;
|
||||
| ^^^^^^^^^^^
|
||||
|
|
@ -48,7 +48,7 @@ LL | 1f32 as i32;
|
|||
= help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]`
|
||||
|
||||
error: casting `f32` to `u32` may truncate the value
|
||||
--> tests/ui/cast.rs:45:5
|
||||
--> tests/ui/cast.rs:44:5
|
||||
|
|
||||
LL | 1f32 as u32;
|
||||
| ^^^^^^^^^^^
|
||||
|
|
@ -56,7 +56,7 @@ LL | 1f32 as u32;
|
|||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||
|
||||
error: casting `f32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:45:5
|
||||
--> tests/ui/cast.rs:44:5
|
||||
|
|
||||
LL | 1f32 as u32;
|
||||
| ^^^^^^^^^^^
|
||||
|
|
@ -65,7 +65,7 @@ LL | 1f32 as u32;
|
|||
= help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]`
|
||||
|
||||
error: casting `f64` to `f32` may truncate the value
|
||||
--> tests/ui/cast.rs:49:5
|
||||
--> tests/ui/cast.rs:48:5
|
||||
|
|
||||
LL | 1f64 as f32;
|
||||
| ^^^^^^^^^^^
|
||||
|
|
@ -73,7 +73,7 @@ LL | 1f64 as f32;
|
|||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||
|
||||
error: casting `i32` to `i8` may truncate the value
|
||||
--> tests/ui/cast.rs:51:5
|
||||
--> tests/ui/cast.rs:50:5
|
||||
|
|
||||
LL | 1i32 as i8;
|
||||
| ^^^^^^^^^^
|
||||
|
|
@ -85,7 +85,7 @@ LL | i8::try_from(1i32);
|
|||
| ~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: casting `i32` to `u8` may truncate the value
|
||||
--> tests/ui/cast.rs:53:5
|
||||
--> tests/ui/cast.rs:52:5
|
||||
|
|
||||
LL | 1i32 as u8;
|
||||
| ^^^^^^^^^^
|
||||
|
|
@ -97,7 +97,7 @@ LL | u8::try_from(1i32);
|
|||
| ~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: casting `f64` to `isize` may truncate the value
|
||||
--> tests/ui/cast.rs:55:5
|
||||
--> tests/ui/cast.rs:54:5
|
||||
|
|
||||
LL | 1f64 as isize;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
@ -105,7 +105,7 @@ LL | 1f64 as isize;
|
|||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||
|
||||
error: casting `f64` to `usize` may truncate the value
|
||||
--> tests/ui/cast.rs:57:5
|
||||
--> tests/ui/cast.rs:56:5
|
||||
|
|
||||
LL | 1f64 as usize;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
@ -113,13 +113,13 @@ LL | 1f64 as usize;
|
|||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||
|
||||
error: casting `f64` to `usize` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:57:5
|
||||
--> tests/ui/cast.rs:56:5
|
||||
|
|
||||
LL | 1f64 as usize;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: casting `u32` to `u16` may truncate the value
|
||||
--> tests/ui/cast.rs:60:5
|
||||
--> tests/ui/cast.rs:59:5
|
||||
|
|
||||
LL | 1f32 as u32 as u16;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -131,7 +131,7 @@ LL | u16::try_from(1f32 as u32);
|
|||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: casting `f32` to `u32` may truncate the value
|
||||
--> tests/ui/cast.rs:60:5
|
||||
--> tests/ui/cast.rs:59:5
|
||||
|
|
||||
LL | 1f32 as u32 as u16;
|
||||
| ^^^^^^^^^^^
|
||||
|
|
@ -139,13 +139,13 @@ LL | 1f32 as u32 as u16;
|
|||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||
|
||||
error: casting `f32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:60:5
|
||||
--> tests/ui/cast.rs:59:5
|
||||
|
|
||||
LL | 1f32 as u32 as u16;
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `i8` may truncate the value
|
||||
--> tests/ui/cast.rs:65:22
|
||||
--> tests/ui/cast.rs:64:22
|
||||
|
|
||||
LL | let _x: i8 = 1i32 as _;
|
||||
| ^^^^^^^^^
|
||||
|
|
@ -157,7 +157,7 @@ LL | let _x: i8 = 1i32.try_into();
|
|||
| ~~~~~~~~~~~~~~~
|
||||
|
||||
error: casting `f32` to `i32` may truncate the value
|
||||
--> tests/ui/cast.rs:67:9
|
||||
--> tests/ui/cast.rs:66:9
|
||||
|
|
||||
LL | 1f32 as i32;
|
||||
| ^^^^^^^^^^^
|
||||
|
|
@ -165,7 +165,7 @@ LL | 1f32 as i32;
|
|||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||
|
||||
error: casting `f64` to `i32` may truncate the value
|
||||
--> tests/ui/cast.rs:69:9
|
||||
--> tests/ui/cast.rs:68:9
|
||||
|
|
||||
LL | 1f64 as i32;
|
||||
| ^^^^^^^^^^^
|
||||
|
|
@ -173,7 +173,7 @@ LL | 1f64 as i32;
|
|||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||
|
||||
error: casting `f32` to `u8` may truncate the value
|
||||
--> tests/ui/cast.rs:71:9
|
||||
--> tests/ui/cast.rs:70:9
|
||||
|
|
||||
LL | 1f32 as u8;
|
||||
| ^^^^^^^^^^
|
||||
|
|
@ -181,13 +181,13 @@ LL | 1f32 as u8;
|
|||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||
|
||||
error: casting `f32` to `u8` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:71:9
|
||||
--> tests/ui/cast.rs:70:9
|
||||
|
|
||||
LL | 1f32 as u8;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: casting `u8` to `i8` may wrap around the value
|
||||
--> tests/ui/cast.rs:76:5
|
||||
--> tests/ui/cast.rs:75:5
|
||||
|
|
||||
LL | 1u8 as i8;
|
||||
| ^^^^^^^^^
|
||||
|
|
@ -196,31 +196,31 @@ LL | 1u8 as i8;
|
|||
= help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]`
|
||||
|
||||
error: casting `u16` to `i16` may wrap around the value
|
||||
--> tests/ui/cast.rs:79:5
|
||||
--> tests/ui/cast.rs:78:5
|
||||
|
|
||||
LL | 1u16 as i16;
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: casting `u32` to `i32` may wrap around the value
|
||||
--> tests/ui/cast.rs:81:5
|
||||
--> tests/ui/cast.rs:80:5
|
||||
|
|
||||
LL | 1u32 as i32;
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: casting `u64` to `i64` may wrap around the value
|
||||
--> tests/ui/cast.rs:83:5
|
||||
--> tests/ui/cast.rs:82:5
|
||||
|
|
||||
LL | 1u64 as i64;
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: casting `usize` to `isize` may wrap around the value
|
||||
--> tests/ui/cast.rs:85:5
|
||||
--> tests/ui/cast.rs:84:5
|
||||
|
|
||||
LL | 1usize as isize;
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `usize` to `i8` may truncate the value
|
||||
--> tests/ui/cast.rs:88:5
|
||||
--> tests/ui/cast.rs:87:5
|
||||
|
|
||||
LL | 1usize as i8;
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
@ -232,7 +232,7 @@ LL | i8::try_from(1usize);
|
|||
| ~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: casting `usize` to `i16` may truncate the value
|
||||
--> tests/ui/cast.rs:91:5
|
||||
--> tests/ui/cast.rs:90:5
|
||||
|
|
||||
LL | 1usize as i16;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
@ -244,7 +244,7 @@ LL | i16::try_from(1usize);
|
|||
| ~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers
|
||||
--> tests/ui/cast.rs:91:5
|
||||
--> tests/ui/cast.rs:90:5
|
||||
|
|
||||
LL | 1usize as i16;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
@ -253,7 +253,7 @@ LL | 1usize as i16;
|
|||
= note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
|
||||
|
||||
error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers
|
||||
--> tests/ui/cast.rs:96:5
|
||||
--> tests/ui/cast.rs:95:5
|
||||
|
|
||||
LL | 1usize as i32;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
@ -265,19 +265,19 @@ LL | i32::try_from(1usize);
|
|||
| ~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers
|
||||
--> tests/ui/cast.rs:96:5
|
||||
--> tests/ui/cast.rs:95:5
|
||||
|
|
||||
LL | 1usize as i32;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers
|
||||
--> tests/ui/cast.rs:100:5
|
||||
--> tests/ui/cast.rs:99:5
|
||||
|
|
||||
LL | 1usize as i64;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers
|
||||
--> tests/ui/cast.rs:105:5
|
||||
--> tests/ui/cast.rs:104:5
|
||||
|
|
||||
LL | 1u16 as isize;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
@ -286,13 +286,13 @@ LL | 1u16 as isize;
|
|||
= note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
|
||||
|
||||
error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers
|
||||
--> tests/ui/cast.rs:109:5
|
||||
--> tests/ui/cast.rs:108:5
|
||||
|
|
||||
LL | 1u32 as isize;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers
|
||||
--> tests/ui/cast.rs:112:5
|
||||
--> tests/ui/cast.rs:111:5
|
||||
|
|
||||
LL | 1u64 as isize;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
@ -304,55 +304,55 @@ LL | isize::try_from(1u64);
|
|||
| ~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers
|
||||
--> tests/ui/cast.rs:112:5
|
||||
--> tests/ui/cast.rs:111:5
|
||||
|
|
||||
LL | 1u64 as isize;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:117:5
|
||||
--> tests/ui/cast.rs:116:5
|
||||
|
|
||||
LL | -1i32 as u32;
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: casting `isize` to `usize` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:120:5
|
||||
--> tests/ui/cast.rs:119:5
|
||||
|
|
||||
LL | -1isize as usize;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i8` to `u8` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:131:5
|
||||
--> tests/ui/cast.rs:130:5
|
||||
|
|
||||
LL | (i8::MIN).abs() as u8;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i64` to `u64` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:135:5
|
||||
--> tests/ui/cast.rs:134:5
|
||||
|
|
||||
LL | (-1i64).abs() as u64;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `isize` to `usize` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:136:5
|
||||
--> tests/ui/cast.rs:135:5
|
||||
|
|
||||
LL | (-1isize).abs() as usize;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i64` to `u64` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:143:5
|
||||
--> tests/ui/cast.rs:142:5
|
||||
|
|
||||
LL | (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i64` to `u64` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:158:5
|
||||
--> tests/ui/cast.rs:157:5
|
||||
|
|
||||
LL | (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i64` to `i8` may truncate the value
|
||||
--> tests/ui/cast.rs:209:5
|
||||
--> tests/ui/cast.rs:208:5
|
||||
|
|
||||
LL | (-99999999999i64).min(1) as i8;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -364,7 +364,7 @@ LL | i8::try_from((-99999999999i64).min(1));
|
|||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: casting `u64` to `u8` may truncate the value
|
||||
--> tests/ui/cast.rs:223:5
|
||||
--> tests/ui/cast.rs:222:5
|
||||
|
|
||||
LL | 999999u64.clamp(0, 256) as u8;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -376,7 +376,7 @@ LL | u8::try_from(999999u64.clamp(0, 256));
|
|||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: casting `main::E2` to `u8` may truncate the value
|
||||
--> tests/ui/cast.rs:246:21
|
||||
--> tests/ui/cast.rs:245:21
|
||||
|
|
||||
LL | let _ = self as u8;
|
||||
| ^^^^^^^^^^
|
||||
|
|
@ -388,7 +388,7 @@ LL | let _ = u8::try_from(self);
|
|||
| ~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: casting `main::E2::B` to `u8` will truncate the value
|
||||
--> tests/ui/cast.rs:248:21
|
||||
--> tests/ui/cast.rs:247:21
|
||||
|
|
||||
LL | let _ = Self::B as u8;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
@ -397,7 +397,7 @@ LL | let _ = Self::B as u8;
|
|||
= help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]`
|
||||
|
||||
error: casting `main::E5` to `i8` may truncate the value
|
||||
--> tests/ui/cast.rs:290:21
|
||||
--> tests/ui/cast.rs:289:21
|
||||
|
|
||||
LL | let _ = self as i8;
|
||||
| ^^^^^^^^^^
|
||||
|
|
@ -409,13 +409,13 @@ LL | let _ = i8::try_from(self);
|
|||
| ~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: casting `main::E5::A` to `i8` will truncate the value
|
||||
--> tests/ui/cast.rs:292:21
|
||||
--> tests/ui/cast.rs:291:21
|
||||
|
|
||||
LL | let _ = Self::A as i8;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: casting `main::E6` to `i16` may truncate the value
|
||||
--> tests/ui/cast.rs:309:21
|
||||
--> tests/ui/cast.rs:308:21
|
||||
|
|
||||
LL | let _ = self as i16;
|
||||
| ^^^^^^^^^^^
|
||||
|
|
@ -427,7 +427,7 @@ LL | let _ = i16::try_from(self);
|
|||
| ~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers
|
||||
--> tests/ui/cast.rs:328:21
|
||||
--> tests/ui/cast.rs:327:21
|
||||
|
|
||||
LL | let _ = self as usize;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
@ -439,7 +439,7 @@ LL | let _ = usize::try_from(self);
|
|||
| ~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: casting `main::E10` to `u16` may truncate the value
|
||||
--> tests/ui/cast.rs:375:21
|
||||
--> tests/ui/cast.rs:374:21
|
||||
|
|
||||
LL | let _ = self as u16;
|
||||
| ^^^^^^^^^^^
|
||||
|
|
@ -451,7 +451,7 @@ LL | let _ = u16::try_from(self);
|
|||
| ~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: casting `u32` to `u8` may truncate the value
|
||||
--> tests/ui/cast.rs:386:13
|
||||
--> tests/ui/cast.rs:385:13
|
||||
|
|
||||
LL | let c = (q >> 16) as u8;
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
@ -463,7 +463,7 @@ LL | let c = u8::try_from(q >> 16);
|
|||
| ~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: casting `u32` to `u8` may truncate the value
|
||||
--> tests/ui/cast.rs:390:13
|
||||
--> tests/ui/cast.rs:389:13
|
||||
|
|
||||
LL | let c = (q / 1000) as u8;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
@ -475,85 +475,85 @@ LL | let c = u8::try_from(q / 1000);
|
|||
| ~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:402:9
|
||||
--> tests/ui/cast.rs:401:9
|
||||
|
|
||||
LL | (x * x) as u32;
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:407:32
|
||||
--> tests/ui/cast.rs:406:32
|
||||
|
|
||||
LL | let _a = |x: i32| -> u32 { (x * x * x * x) as u32 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:409:5
|
||||
--> tests/ui/cast.rs:408:5
|
||||
|
|
||||
LL | (2_i32).checked_pow(3).unwrap() as u32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:410:5
|
||||
--> tests/ui/cast.rs:409:5
|
||||
|
|
||||
LL | (-2_i32).pow(3) as u32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:415:5
|
||||
--> tests/ui/cast.rs:414:5
|
||||
|
|
||||
LL | (-5_i32 % 2) as u32;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:417:5
|
||||
--> tests/ui/cast.rs:416:5
|
||||
|
|
||||
LL | (-5_i32 % -2) as u32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:420:5
|
||||
--> tests/ui/cast.rs:419:5
|
||||
|
|
||||
LL | (-2_i32 >> 1) as u32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:424:5
|
||||
--> tests/ui/cast.rs:423:5
|
||||
|
|
||||
LL | (x * x) as u32;
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:425:5
|
||||
--> tests/ui/cast.rs:424:5
|
||||
|
|
||||
LL | (x * x * x) as u32;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i16` to `u16` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:429:5
|
||||
--> tests/ui/cast.rs:428:5
|
||||
|
|
||||
LL | (y * y * y * y * -2) as u16;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i16` to `u16` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:431:5
|
||||
--> tests/ui/cast.rs:430:5
|
||||
|
|
||||
LL | (y * y * y / y * 2) as u16;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i16` to `u16` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:432:5
|
||||
--> tests/ui/cast.rs:431:5
|
||||
|
|
||||
LL | (y * y / y * 2) as u16;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i16` to `u16` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:434:5
|
||||
--> tests/ui/cast.rs:433:5
|
||||
|
|
||||
LL | (y / y * y * -2) as u16;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `/`
|
||||
--> tests/ui/cast.rs:434:6
|
||||
--> tests/ui/cast.rs:433:6
|
||||
|
|
||||
LL | (y / y * y * -2) as u16;
|
||||
| ^^^^^
|
||||
|
|
@ -561,97 +561,97 @@ LL | (y / y * y * -2) as u16;
|
|||
= note: `#[deny(clippy::eq_op)]` on by default
|
||||
|
||||
error: casting `i16` to `u16` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:437:5
|
||||
--> tests/ui/cast.rs:436:5
|
||||
|
|
||||
LL | (y + y + y + -2) as u16;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i16` to `u16` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:439:5
|
||||
--> tests/ui/cast.rs:438:5
|
||||
|
|
||||
LL | (y + y + y + 2) as u16;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i16` to `u16` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:443:5
|
||||
--> tests/ui/cast.rs:442:5
|
||||
|
|
||||
LL | (z + -2) as u16;
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i16` to `u16` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:445:5
|
||||
--> tests/ui/cast.rs:444:5
|
||||
|
|
||||
LL | (z + z + 2) as u16;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:448:9
|
||||
--> tests/ui/cast.rs:447:9
|
||||
|
|
||||
LL | (a * a * b * b * c * c) as u32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:449:9
|
||||
--> tests/ui/cast.rs:448:9
|
||||
|
|
||||
LL | (a * b * c) as u32;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:451:9
|
||||
--> tests/ui/cast.rs:450:9
|
||||
|
|
||||
LL | (a * -b * c) as u32;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:453:9
|
||||
--> tests/ui/cast.rs:452:9
|
||||
|
|
||||
LL | (a * b * c * c) as u32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:454:9
|
||||
--> tests/ui/cast.rs:453:9
|
||||
|
|
||||
LL | (a * -2) as u32;
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:456:9
|
||||
--> tests/ui/cast.rs:455:9
|
||||
|
|
||||
LL | (a * b * c * -2) as u32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:458:9
|
||||
--> tests/ui/cast.rs:457:9
|
||||
|
|
||||
LL | (a / b) as u32;
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:459:9
|
||||
--> tests/ui/cast.rs:458:9
|
||||
|
|
||||
LL | (a / b * c) as u32;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:461:9
|
||||
--> tests/ui/cast.rs:460:9
|
||||
|
|
||||
LL | (a / b + b * c) as u32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:463:9
|
||||
--> tests/ui/cast.rs:462:9
|
||||
|
|
||||
LL | a.saturating_pow(3) as u32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:465:9
|
||||
--> tests/ui/cast.rs:464:9
|
||||
|
|
||||
LL | (a.abs() * b.pow(2) / c.abs()) as u32
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `i32` to `u32` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:473:21
|
||||
--> tests/ui/cast.rs:472:21
|
||||
|
|
||||
LL | let _ = i32::MIN as u32; // cast_sign_loss
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
@ -662,7 +662,7 @@ LL | m!();
|
|||
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: casting `u32` to `u8` may truncate the value
|
||||
--> tests/ui/cast.rs:474:21
|
||||
--> tests/ui/cast.rs:473:21
|
||||
|
|
||||
LL | let _ = u32::MAX as u8; // cast_possible_truncation
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
@ -678,7 +678,7 @@ LL | let _ = u8::try_from(u32::MAX); // cast_possible_truncation
|
|||
| ~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: casting `f64` to `f32` may truncate the value
|
||||
--> tests/ui/cast.rs:475:21
|
||||
--> tests/ui/cast.rs:474:21
|
||||
|
|
||||
LL | let _ = std::f64::consts::PI as f32; // cast_possible_truncation
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -690,7 +690,7 @@ LL | m!();
|
|||
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
|
||||
--> tests/ui/cast.rs:484:5
|
||||
--> tests/ui/cast.rs:483:5
|
||||
|
|
||||
LL | bar.unwrap().unwrap() as usize
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -702,13 +702,13 @@ LL | usize::try_from(bar.unwrap().unwrap())
|
|||
|
|
||||
|
||||
error: casting `i64` to `usize` may lose the sign of the value
|
||||
--> tests/ui/cast.rs:484:5
|
||||
--> tests/ui/cast.rs:483:5
|
||||
|
|
||||
LL | bar.unwrap().unwrap() as usize
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `u64` to `u8` may truncate the value
|
||||
--> tests/ui/cast.rs:499:5
|
||||
--> tests/ui/cast.rs:498:5
|
||||
|
|
||||
LL | (256 & 999999u64) as u8;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -720,7 +720,7 @@ LL | u8::try_from(256 & 999999u64);
|
|||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: casting `u64` to `u8` may truncate the value
|
||||
--> tests/ui/cast.rs:501:5
|
||||
--> tests/ui/cast.rs:500:5
|
||||
|
|
||||
LL | (255 % 999999u64) as u8;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#![warn(clippy::missing_const_for_fn)]
|
||||
#![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)]
|
||||
#![allow(unsupported_calling_conventions)]
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(const_trait_impl, abi_vectorcall)]
|
||||
|
||||
|
||||
use std::mem::transmute;
|
||||
|
||||
|
|
@ -212,8 +212,8 @@ mod extern_fn {
|
|||
//~^ ERROR: this could be a `const fn`
|
||||
const extern "system-unwind" fn system_unwind() {}
|
||||
//~^ ERROR: this could be a `const fn`
|
||||
pub const extern "stdcall" fn std_call() {}
|
||||
pub const extern "vectorcall" fn std_call() {}
|
||||
//~^ ERROR: this could be a `const fn`
|
||||
pub const extern "stdcall-unwind" fn std_call_unwind() {}
|
||||
pub const extern "vectorcall-unwind" fn std_call_unwind() {}
|
||||
//~^ ERROR: this could be a `const fn`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#![warn(clippy::missing_const_for_fn)]
|
||||
#![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)]
|
||||
#![allow(unsupported_calling_conventions)]
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(const_trait_impl, abi_vectorcall)]
|
||||
|
||||
|
||||
use std::mem::transmute;
|
||||
|
||||
|
|
@ -212,8 +212,8 @@ mod extern_fn {
|
|||
//~^ ERROR: this could be a `const fn`
|
||||
extern "system-unwind" fn system_unwind() {}
|
||||
//~^ ERROR: this could be a `const fn`
|
||||
pub extern "stdcall" fn std_call() {}
|
||||
pub extern "vectorcall" fn std_call() {}
|
||||
//~^ ERROR: this could be a `const fn`
|
||||
pub extern "stdcall-unwind" fn std_call_unwind() {}
|
||||
pub extern "vectorcall-unwind" fn std_call_unwind() {}
|
||||
//~^ ERROR: this could be a `const fn`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -319,23 +319,23 @@ LL | const extern "system-unwind" fn system_unwind() {}
|
|||
error: this could be a `const fn`
|
||||
--> tests/ui/missing_const_for_fn/could_be_const.rs:215:5
|
||||
|
|
||||
LL | pub extern "stdcall" fn std_call() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | pub extern "vectorcall" fn std_call() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: make the function `const`
|
||||
|
|
||||
LL | pub const extern "stdcall" fn std_call() {}
|
||||
LL | pub const extern "vectorcall" fn std_call() {}
|
||||
| +++++
|
||||
|
||||
error: this could be a `const fn`
|
||||
--> tests/ui/missing_const_for_fn/could_be_const.rs:217:5
|
||||
|
|
||||
LL | pub extern "stdcall-unwind" fn std_call_unwind() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | pub extern "vectorcall-unwind" fn std_call_unwind() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: make the function `const`
|
||||
|
|
||||
LL | pub const extern "stdcall-unwind" fn std_call_unwind() {}
|
||||
LL | pub const extern "vectorcall-unwind" fn std_call_unwind() {}
|
||||
| +++++
|
||||
|
||||
error: aborting due to 26 previous errors
|
||||
|
|
|
|||
3
src/tools/clippy/tests/ui/no_lints.rs
Normal file
3
src/tools/clippy/tests/ui/no_lints.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#![deny(clippy::all)]
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -54,7 +54,7 @@
|
|||
#![allow(enum_intrinsics_non_enums)]
|
||||
#![allow(non_fmt_panics)]
|
||||
#![allow(named_arguments_used_positionally)]
|
||||
#![allow(temporary_cstring_as_ptr)]
|
||||
#![allow(dangling_pointers_from_temporaries)]
|
||||
#![allow(undropped_manually_drops)]
|
||||
#![allow(unknown_lints)]
|
||||
#![allow(unused_labels)]
|
||||
|
|
@ -120,7 +120,7 @@
|
|||
#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::mismatched_target_os`
|
||||
#![warn(non_fmt_panics)] //~ ERROR: lint `clippy::panic_params`
|
||||
#![warn(named_arguments_used_positionally)] //~ ERROR: lint `clippy::positional_named_format_parameters`
|
||||
#![warn(temporary_cstring_as_ptr)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
|
||||
#![warn(dangling_pointers_from_temporaries)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
|
||||
#![warn(undropped_manually_drops)] //~ ERROR: lint `clippy::undropped_manually_drops`
|
||||
#![warn(unknown_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints`
|
||||
#![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label`
|
||||
|
|
|
|||
|
|
@ -1,11 +1,17 @@
|
|||
error: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
|
||||
--> tests/ui/rename.rs:57:10
|
||||
|
|
||||
LL | #![allow(temporary_cstring_as_ptr)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
|
||||
|
|
||||
= note: `-D renamed-and-removed-lints` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
|
||||
|
||||
error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
|
||||
--> tests/ui/rename.rs:63:9
|
||||
|
|
||||
LL | #![warn(clippy::almost_complete_letter_range)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
|
||||
|
|
||||
= note: `-D renamed-and-removed-lints` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
|
||||
|
||||
error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
|
||||
--> tests/ui/rename.rs:64:9
|
||||
|
|
@ -361,11 +367,11 @@ error: lint `clippy::positional_named_format_parameters` has been renamed to `na
|
|||
LL | #![warn(clippy::positional_named_format_parameters)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
|
||||
|
||||
error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
|
||||
error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
|
||||
--> tests/ui/rename.rs:123:9
|
||||
|
|
||||
LL | #![warn(clippy::temporary_cstring_as_ptr)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
|
||||
|
||||
error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
|
||||
--> tests/ui/rename.rs:124:9
|
||||
|
|
@ -397,5 +403,5 @@ error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_e
|
|||
LL | #![warn(clippy::reverse_range_loop)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
|
||||
|
||||
error: aborting due to 66 previous errors
|
||||
error: aborting due to 67 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -376,6 +376,7 @@ pub struct Config {
|
|||
pub only_modified: bool,
|
||||
|
||||
pub target_cfgs: OnceLock<TargetCfgs>,
|
||||
pub builtin_cfg_names: OnceLock<HashSet<String>>,
|
||||
|
||||
pub nocapture: bool,
|
||||
|
||||
|
|
@ -387,6 +388,9 @@ pub struct Config {
|
|||
/// True if the profiler runtime is enabled for this target.
|
||||
/// Used by the "needs-profiler-runtime" directive in test files.
|
||||
pub profiler_runtime: bool,
|
||||
|
||||
/// Command for visual diff display, e.g. `diff-tool --color=always`.
|
||||
pub diff_command: Option<String>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
|
|
@ -440,6 +444,11 @@ impl Config {
|
|||
self.target_cfg().panic == PanicStrategy::Unwind
|
||||
}
|
||||
|
||||
/// Get the list of builtin, 'well known' cfg names
|
||||
pub fn builtin_cfg_names(&self) -> &HashSet<String> {
|
||||
self.builtin_cfg_names.get_or_init(|| builtin_cfg_names(self))
|
||||
}
|
||||
|
||||
pub fn has_threads(&self) -> bool {
|
||||
// Wasm targets don't have threads unless `-threads` is in the target
|
||||
// name, such as `wasm32-wasip1-threads`.
|
||||
|
|
@ -651,6 +660,18 @@ pub enum Endian {
|
|||
Big,
|
||||
}
|
||||
|
||||
fn builtin_cfg_names(config: &Config) -> HashSet<String> {
|
||||
rustc_output(
|
||||
config,
|
||||
&["--print=check-cfg", "-Zunstable-options", "--check-cfg=cfg()"],
|
||||
Default::default(),
|
||||
)
|
||||
.lines()
|
||||
.map(|l| if let Some((name, _)) = l.split_once('=') { name.to_string() } else { l.to_string() })
|
||||
.chain(std::iter::once(String::from("test")))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn rustc_output(config: &Config, args: &[&str], envs: HashMap<String, String>) -> String {
|
||||
let mut command = Command::new(&config.rustc_path);
|
||||
add_dylib_path(&mut command, iter::once(&config.compile_lib_path));
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ impl EarlyProps {
|
|||
&mut poisoned,
|
||||
testfile,
|
||||
rdr,
|
||||
&mut |DirectiveLine { directive: ln, .. }| {
|
||||
&mut |DirectiveLine { raw_directive: ln, .. }| {
|
||||
parse_and_update_aux(config, ln, &mut props.aux);
|
||||
config.parse_and_update_revisions(testfile, ln, &mut props.revisions);
|
||||
},
|
||||
|
|
@ -344,8 +344,8 @@ impl TestProps {
|
|||
&mut poisoned,
|
||||
testfile,
|
||||
file,
|
||||
&mut |DirectiveLine { header_revision, directive: ln, .. }| {
|
||||
if header_revision.is_some() && header_revision != test_revision {
|
||||
&mut |directive @ DirectiveLine { raw_directive: ln, .. }| {
|
||||
if !directive.applies_to_test_revision(test_revision) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -678,35 +678,42 @@ impl TestProps {
|
|||
}
|
||||
}
|
||||
|
||||
/// Extract an `(Option<line_revision>, directive)` directive from a line if comment is present.
|
||||
///
|
||||
/// See [`DirectiveLine`] for a diagram.
|
||||
pub fn line_directive<'line>(
|
||||
/// If the given line begins with the appropriate comment prefix for a directive,
|
||||
/// returns a struct containing various parts of the directive.
|
||||
fn line_directive<'line>(
|
||||
line_number: usize,
|
||||
comment: &str,
|
||||
original_line: &'line str,
|
||||
) -> Option<(Option<&'line str>, &'line str)> {
|
||||
) -> Option<DirectiveLine<'line>> {
|
||||
// Ignore lines that don't start with the comment prefix.
|
||||
let after_comment = original_line.trim_start().strip_prefix(comment)?.trim_start();
|
||||
|
||||
let revision;
|
||||
let raw_directive;
|
||||
|
||||
if let Some(after_open_bracket) = after_comment.strip_prefix('[') {
|
||||
// A comment like `//@[foo]` only applies to revision `foo`.
|
||||
let Some((line_revision, directive)) = after_open_bracket.split_once(']') else {
|
||||
let Some((line_revision, after_close_bracket)) = after_open_bracket.split_once(']') else {
|
||||
panic!(
|
||||
"malformed condition directive: expected `{comment}[foo]`, found `{original_line}`"
|
||||
)
|
||||
};
|
||||
|
||||
Some((Some(line_revision), directive.trim_start()))
|
||||
revision = Some(line_revision);
|
||||
raw_directive = after_close_bracket.trim_start();
|
||||
} else {
|
||||
Some((None, after_comment))
|
||||
}
|
||||
revision = None;
|
||||
raw_directive = after_comment;
|
||||
};
|
||||
|
||||
Some(DirectiveLine { line_number, revision, raw_directive })
|
||||
}
|
||||
|
||||
// To prevent duplicating the list of commmands between `compiletest`,`htmldocck` and `jsondocck`,
|
||||
// To prevent duplicating the list of directives between `compiletest`,`htmldocck` and `jsondocck`,
|
||||
// we put it into a common file which is included in rust code and parsed here.
|
||||
// FIXME: This setup is temporary until we figure out how to improve this situation.
|
||||
// See <https://github.com/rust-lang/rust/issues/125813#issuecomment-2141953780>.
|
||||
include!("command-list.rs");
|
||||
include!("directive-list.rs");
|
||||
|
||||
const KNOWN_HTMLDOCCK_DIRECTIVE_NAMES: &[&str] = &[
|
||||
"count",
|
||||
|
|
@ -730,28 +737,37 @@ const KNOWN_HTMLDOCCK_DIRECTIVE_NAMES: &[&str] = &[
|
|||
const KNOWN_JSONDOCCK_DIRECTIVE_NAMES: &[&str] =
|
||||
&["count", "!count", "has", "!has", "is", "!is", "ismany", "!ismany", "set", "!set"];
|
||||
|
||||
/// The broken-down contents of a line containing a test header directive,
|
||||
/// The (partly) broken-down contents of a line containing a test directive,
|
||||
/// which [`iter_header`] passes to its callback function.
|
||||
///
|
||||
/// For example:
|
||||
///
|
||||
/// ```text
|
||||
/// //@ compile-flags: -O
|
||||
/// ^^^^^^^^^^^^^^^^^ directive
|
||||
/// ^^^^^^^^^^^^^^^^^ raw_directive
|
||||
///
|
||||
/// //@ [foo] compile-flags: -O
|
||||
/// ^^^ header_revision
|
||||
/// ^^^^^^^^^^^^^^^^^ directive
|
||||
/// ^^^ revision
|
||||
/// ^^^^^^^^^^^^^^^^^ raw_directive
|
||||
/// ```
|
||||
struct DirectiveLine<'ln> {
|
||||
line_number: usize,
|
||||
/// Some header directives start with a revision name in square brackets
|
||||
/// Some test directives start with a revision name in square brackets
|
||||
/// (e.g. `[foo]`), and only apply to that revision of the test.
|
||||
/// If present, this field contains the revision name (e.g. `foo`).
|
||||
header_revision: Option<&'ln str>,
|
||||
/// The main part of the header directive, after removing the comment prefix
|
||||
revision: Option<&'ln str>,
|
||||
/// The main part of the directive, after removing the comment prefix
|
||||
/// and the optional revision specifier.
|
||||
directive: &'ln str,
|
||||
///
|
||||
/// This is "raw" because the directive's name and colon-separated value
|
||||
/// (if present) have not yet been extracted or checked.
|
||||
raw_directive: &'ln str,
|
||||
}
|
||||
|
||||
impl<'ln> DirectiveLine<'ln> {
|
||||
fn applies_to_test_revision(&self, test_revision: Option<&str>) -> bool {
|
||||
self.revision.is_none() || self.revision == test_revision
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CheckDirectiveResult<'ln> {
|
||||
|
|
@ -819,8 +835,8 @@ fn iter_header(
|
|||
"ignore-cross-compile",
|
||||
];
|
||||
// Process the extra implied directives, with a dummy line number of 0.
|
||||
for directive in extra_directives {
|
||||
it(DirectiveLine { line_number: 0, header_revision: None, directive });
|
||||
for raw_directive in extra_directives {
|
||||
it(DirectiveLine { line_number: 0, revision: None, raw_directive });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -847,24 +863,21 @@ fn iter_header(
|
|||
return;
|
||||
}
|
||||
|
||||
let Some((header_revision, non_revisioned_directive_line)) = line_directive(comment, ln)
|
||||
else {
|
||||
let Some(directive_line) = line_directive(line_number, comment, ln) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
// Perform unknown directive check on Rust files.
|
||||
if testfile.extension().map(|e| e == "rs").unwrap_or(false) {
|
||||
let directive_ln = non_revisioned_directive_line.trim();
|
||||
|
||||
let CheckDirectiveResult { is_known_directive, trailing_directive } =
|
||||
check_directive(directive_ln, mode, ln);
|
||||
check_directive(directive_line.raw_directive, mode, ln);
|
||||
|
||||
if !is_known_directive {
|
||||
*poisoned = true;
|
||||
|
||||
eprintln!(
|
||||
"error: detected unknown compiletest test directive `{}` in {}:{}",
|
||||
directive_ln,
|
||||
directive_line.raw_directive,
|
||||
testfile.display(),
|
||||
line_number,
|
||||
);
|
||||
|
|
@ -888,11 +901,7 @@ fn iter_header(
|
|||
}
|
||||
}
|
||||
|
||||
it(DirectiveLine {
|
||||
line_number,
|
||||
header_revision,
|
||||
directive: non_revisioned_directive_line,
|
||||
});
|
||||
it(directive_line);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1292,8 +1301,8 @@ pub fn make_test_description<R: Read>(
|
|||
&mut local_poisoned,
|
||||
path,
|
||||
src,
|
||||
&mut |DirectiveLine { header_revision, directive: ln, line_number }| {
|
||||
if header_revision.is_some() && header_revision != test_revision {
|
||||
&mut |directive @ DirectiveLine { line_number, raw_directive: ln, .. }| {
|
||||
if !directive.applies_to_test_revision(test_revision) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -175,6 +175,12 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
"git-merge-commit-email",
|
||||
"email address used for finding merge commits",
|
||||
"EMAIL",
|
||||
)
|
||||
.optopt(
|
||||
"",
|
||||
"compiletest-diff-tool",
|
||||
"What custom diff tool to use for displaying compiletest tests.",
|
||||
"COMMAND",
|
||||
);
|
||||
|
||||
let (argv0, args_) = args.split_first().unwrap();
|
||||
|
|
@ -356,6 +362,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
force_rerun: matches.opt_present("force-rerun"),
|
||||
|
||||
target_cfgs: OnceLock::new(),
|
||||
builtin_cfg_names: OnceLock::new(),
|
||||
|
||||
nocapture: matches.opt_present("nocapture"),
|
||||
|
||||
|
|
@ -364,6 +371,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
git_merge_commit_email: matches.opt_str("git-merge-commit-email").unwrap(),
|
||||
|
||||
profiler_runtime: matches.opt_present("profiler-runtime"),
|
||||
diff_command: matches.opt_str("compiletest-diff-tool"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R {
|
|||
use std::sync::Mutex;
|
||||
|
||||
use windows::Win32::System::Diagnostics::Debug::{
|
||||
SEM_NOGPFAULTERRORBOX, SetErrorMode, THREAD_ERROR_MODE,
|
||||
SEM_FAILCRITICALERRORS, SEM_NOGPFAULTERRORBOX, SetErrorMode, THREAD_ERROR_MODE,
|
||||
};
|
||||
|
||||
static LOCK: Mutex<()> = Mutex::new(());
|
||||
|
|
@ -67,13 +67,21 @@ fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R {
|
|||
// Error mode is a global variable, so lock it so only one thread will change it
|
||||
let _lock = LOCK.lock().unwrap();
|
||||
|
||||
// Tell Windows to not show any UI on errors (such as terminating abnormally).
|
||||
// This is important for running tests, since some of them use abnormal
|
||||
// termination by design. This mode is inherited by all child processes.
|
||||
// Tell Windows to not show any UI on errors (such as terminating abnormally). This is important
|
||||
// for running tests, since some of them use abnormal termination by design. This mode is
|
||||
// inherited by all child processes.
|
||||
//
|
||||
// Note that `run-make` tests require `SEM_FAILCRITICALERRORS` in addition to suppress Windows
|
||||
// Error Reporting (WER) error dialogues that come from "critical failures" such as missing
|
||||
// DLLs.
|
||||
//
|
||||
// See <https://github.com/rust-lang/rust/issues/132092> and
|
||||
// <https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-seterrormode?redirectedfrom=MSDN>.
|
||||
unsafe {
|
||||
let old_mode = SetErrorMode(SEM_NOGPFAULTERRORBOX); // read inherited flags
|
||||
// read inherited flags
|
||||
let old_mode = SetErrorMode(SEM_NOGPFAULTERRORBOX | SEM_FAILCRITICALERRORS);
|
||||
let old_mode = THREAD_ERROR_MODE(old_mode);
|
||||
SetErrorMode(old_mode | SEM_NOGPFAULTERRORBOX);
|
||||
SetErrorMode(old_mode | SEM_NOGPFAULTERRORBOX | SEM_FAILCRITICALERRORS);
|
||||
let r = f();
|
||||
SetErrorMode(old_mode);
|
||||
r
|
||||
|
|
@ -478,6 +486,9 @@ impl<'test> TestCx<'test> {
|
|||
"error: redundant cfg argument `{normalized_revision}` is already created by the revision"
|
||||
);
|
||||
}
|
||||
if self.config.builtin_cfg_names().contains(&normalized_revision) {
|
||||
panic!("error: revision `{normalized_revision}` collides with a builtin cfg");
|
||||
}
|
||||
cmd.args(cfg_arg);
|
||||
}
|
||||
|
||||
|
|
@ -1085,6 +1096,10 @@ impl<'test> TestCx<'test> {
|
|||
self.config.target.contains("vxworks") && !self.is_vxworks_pure_static()
|
||||
}
|
||||
|
||||
fn has_aux_dir(&self) -> bool {
|
||||
!self.props.aux.builds.is_empty() || !self.props.aux.crates.is_empty()
|
||||
}
|
||||
|
||||
fn aux_output_dir(&self) -> PathBuf {
|
||||
let aux_dir = self.aux_output_dir_name();
|
||||
|
||||
|
|
@ -1638,7 +1653,11 @@ impl<'test> TestCx<'test> {
|
|||
}
|
||||
|
||||
if let LinkToAux::Yes = link_to_aux {
|
||||
rustc.arg("-L").arg(self.aux_output_dir_name());
|
||||
// if we pass an `-L` argument to a directory that doesn't exist,
|
||||
// macOS ld emits warnings which disrupt the .stderr files
|
||||
if self.has_aux_dir() {
|
||||
rustc.arg("-L").arg(self.aux_output_dir_name());
|
||||
}
|
||||
}
|
||||
|
||||
rustc.args(&self.props.compile_flags);
|
||||
|
|
@ -2459,7 +2478,7 @@ impl<'test> TestCx<'test> {
|
|||
}
|
||||
}
|
||||
|
||||
fn compare_output(&self, kind: &str, actual: &str, expected: &str) -> usize {
|
||||
fn compare_output(&self, stream: &str, actual: &str, expected: &str) -> usize {
|
||||
let are_different = match (self.force_color_svg(), expected.find('\n'), actual.find('\n')) {
|
||||
// FIXME: We ignore the first line of SVG files
|
||||
// because the width parameter is non-deterministic.
|
||||
|
|
@ -2499,56 +2518,66 @@ impl<'test> TestCx<'test> {
|
|||
(expected, actual)
|
||||
};
|
||||
|
||||
if !self.config.bless {
|
||||
if expected.is_empty() {
|
||||
println!("normalized {}:\n{}\n", kind, actual);
|
||||
} else {
|
||||
println!("diff of {}:\n", kind);
|
||||
print!("{}", write_diff(expected, actual, 3));
|
||||
}
|
||||
}
|
||||
|
||||
let mode = self.config.compare_mode.as_ref().map_or("", |m| m.to_str());
|
||||
let output_file = self
|
||||
// Write the actual output to a file in build/
|
||||
let test_name = self.config.compare_mode.as_ref().map_or("", |m| m.to_str());
|
||||
let actual_path = self
|
||||
.output_base_name()
|
||||
.with_extra_extension(self.revision.unwrap_or(""))
|
||||
.with_extra_extension(mode)
|
||||
.with_extra_extension(kind);
|
||||
.with_extra_extension(test_name)
|
||||
.with_extra_extension(stream);
|
||||
|
||||
let mut files = vec![output_file];
|
||||
if self.config.bless {
|
||||
if let Err(err) = fs::write(&actual_path, &actual) {
|
||||
self.fatal(&format!("failed to write {stream} to `{actual_path:?}`: {err}",));
|
||||
}
|
||||
println!("Saved the actual {stream} to {actual_path:?}");
|
||||
|
||||
let expected_path =
|
||||
expected_output_path(self.testpaths, self.revision, &self.config.compare_mode, stream);
|
||||
|
||||
if !self.config.bless {
|
||||
if expected.is_empty() {
|
||||
println!("normalized {}:\n{}\n", stream, actual);
|
||||
} else {
|
||||
println!("diff of {stream}:\n");
|
||||
if let Some(diff_command) = self.config.diff_command.as_deref() {
|
||||
let mut args = diff_command.split_whitespace();
|
||||
let name = args.next().unwrap();
|
||||
match Command::new(name)
|
||||
.args(args)
|
||||
.args([&expected_path, &actual_path])
|
||||
.output()
|
||||
{
|
||||
Err(err) => {
|
||||
self.fatal(&format!(
|
||||
"failed to call custom diff command `{diff_command}`: {err}"
|
||||
));
|
||||
}
|
||||
Ok(output) => {
|
||||
let output = String::from_utf8_lossy(&output.stdout);
|
||||
print!("{output}");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
print!("{}", write_diff(expected, actual, 3));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Delete non-revision .stderr/.stdout file if revisions are used.
|
||||
// Without this, we'd just generate the new files and leave the old files around.
|
||||
if self.revision.is_some() {
|
||||
let old =
|
||||
expected_output_path(self.testpaths, None, &self.config.compare_mode, kind);
|
||||
expected_output_path(self.testpaths, None, &self.config.compare_mode, stream);
|
||||
self.delete_file(&old);
|
||||
}
|
||||
files.push(expected_output_path(
|
||||
self.testpaths,
|
||||
self.revision,
|
||||
&self.config.compare_mode,
|
||||
kind,
|
||||
));
|
||||
}
|
||||
|
||||
for output_file in &files {
|
||||
if actual.is_empty() {
|
||||
self.delete_file(output_file);
|
||||
} else if let Err(err) = fs::write(&output_file, &actual) {
|
||||
self.fatal(&format!(
|
||||
"failed to write {} to `{}`: {}",
|
||||
kind,
|
||||
output_file.display(),
|
||||
err,
|
||||
));
|
||||
if let Err(err) = fs::write(&expected_path, &actual) {
|
||||
self.fatal(&format!("failed to write {stream} to `{expected_path:?}`: {err}"));
|
||||
}
|
||||
println!("Blessing the {stream} of {test_name} in {expected_path:?}");
|
||||
}
|
||||
|
||||
println!("\nThe actual {0} differed from the expected {0}.", kind);
|
||||
for output_file in files {
|
||||
println!("Actual {} saved to {}", kind, output_file.display());
|
||||
}
|
||||
println!("\nThe actual {0} differed from the expected {0}.", stream);
|
||||
|
||||
if self.config.bless { 0 } else { 1 }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ use std::io::{BufRead, BufReader};
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::common::Config;
|
||||
use crate::header::line_directive;
|
||||
use crate::runtest::ProcRes;
|
||||
|
||||
/// Representation of information to invoke a debugger and check its output
|
||||
|
|
@ -24,7 +23,6 @@ impl DebuggerCommands {
|
|||
file: &Path,
|
||||
config: &Config,
|
||||
debugger_prefixes: &[&str],
|
||||
rev: Option<&str>,
|
||||
) -> Result<Self, String> {
|
||||
let directives = debugger_prefixes
|
||||
.iter()
|
||||
|
|
@ -39,17 +37,16 @@ impl DebuggerCommands {
|
|||
for (line_no, line) in reader.lines().enumerate() {
|
||||
counter += 1;
|
||||
let line = line.map_err(|e| format!("Error while parsing debugger commands: {}", e))?;
|
||||
let (lnrev, line) = line_directive("//", &line).unwrap_or((None, &line));
|
||||
|
||||
// Skip any revision specific directive that doesn't match the current
|
||||
// revision being tested
|
||||
if lnrev.is_some() && lnrev != rev {
|
||||
// Breakpoints appear on lines with actual code, typically at the end of the line.
|
||||
if line.contains("#break") {
|
||||
breakpoint_lines.push(counter);
|
||||
continue;
|
||||
}
|
||||
|
||||
if line.contains("#break") {
|
||||
breakpoint_lines.push(counter);
|
||||
}
|
||||
let Some(line) = line.trim_start().strip_prefix("//").map(str::trim_start) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
for &(ref command_directive, ref check_directive) in &directives {
|
||||
config
|
||||
|
|
|
|||
|
|
@ -66,13 +66,8 @@ impl TestCx<'_> {
|
|||
};
|
||||
|
||||
// Parse debugger commands etc from test files
|
||||
let dbg_cmds = DebuggerCommands::parse_from(
|
||||
&self.testpaths.file,
|
||||
self.config,
|
||||
prefixes,
|
||||
self.revision,
|
||||
)
|
||||
.unwrap_or_else(|e| self.fatal(&e));
|
||||
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes)
|
||||
.unwrap_or_else(|e| self.fatal(&e));
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands
|
||||
let mut script_str = String::with_capacity(2048);
|
||||
|
|
@ -142,13 +137,8 @@ impl TestCx<'_> {
|
|||
}
|
||||
|
||||
fn run_debuginfo_gdb_test_no_opt(&self) {
|
||||
let dbg_cmds = DebuggerCommands::parse_from(
|
||||
&self.testpaths.file,
|
||||
self.config,
|
||||
&["gdb"],
|
||||
self.revision,
|
||||
)
|
||||
.unwrap_or_else(|e| self.fatal(&e));
|
||||
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, &["gdb"])
|
||||
.unwrap_or_else(|e| self.fatal(&e));
|
||||
let mut cmds = dbg_cmds.commands.join("\n");
|
||||
|
||||
// compile test file (it should have 'compile-flags:-g' in the header)
|
||||
|
|
@ -413,13 +403,8 @@ impl TestCx<'_> {
|
|||
}
|
||||
|
||||
// Parse debugger commands etc from test files
|
||||
let dbg_cmds = DebuggerCommands::parse_from(
|
||||
&self.testpaths.file,
|
||||
self.config,
|
||||
&["lldb"],
|
||||
self.revision,
|
||||
)
|
||||
.unwrap_or_else(|e| self.fatal(&e));
|
||||
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, &["lldb"])
|
||||
.unwrap_or_else(|e| self.fatal(&e));
|
||||
|
||||
// Write debugger script:
|
||||
// We don't want to hang when calling `quit` while the process is still running
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::path::Path;
|
|||
use std::process::{Command, Output, Stdio};
|
||||
use std::{env, fs};
|
||||
|
||||
use super::{ProcRes, TestCx};
|
||||
use super::{ProcRes, TestCx, disable_error_reporting};
|
||||
use crate::util::{copy_dir_all, dylib_env_var};
|
||||
|
||||
impl TestCx<'_> {
|
||||
|
|
@ -329,6 +329,7 @@ impl TestCx<'_> {
|
|||
.arg(format!("run_make_support={}", &support_lib_path.to_string_lossy()))
|
||||
.arg("--edition=2021")
|
||||
.arg(&self.testpaths.file.join("rmake.rs"))
|
||||
.arg("-Cprefer-dynamic")
|
||||
// Provide necessary library search paths for rustc.
|
||||
.env(dylib_env_var(), &env::join_paths(host_dylib_search_paths).unwrap());
|
||||
|
||||
|
|
@ -514,8 +515,8 @@ impl TestCx<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
let (Output { stdout, stderr, status }, truncated) =
|
||||
self.read2_abbreviated(cmd.spawn().expect("failed to spawn `rmake`"));
|
||||
let proc = disable_error_reporting(|| cmd.spawn().expect("failed to spawn `rmake`"));
|
||||
let (Output { stdout, stderr, status }, truncated) = self.read2_abbreviated(proc);
|
||||
if !status.success() {
|
||||
let res = ProcRes {
|
||||
status,
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ fn print_err(msg: &str, lineno: usize) {
|
|||
|
||||
// FIXME: This setup is temporary until we figure out how to improve this situation.
|
||||
// See <https://github.com/rust-lang/rust/issues/125813#issuecomment-2141953780>.
|
||||
include!(concat!(env!("CARGO_MANIFEST_DIR"), "/../compiletest/src/command-list.rs"));
|
||||
include!(concat!(env!("CARGO_MANIFEST_DIR"), "/../compiletest/src/directive-list.rs"));
|
||||
|
||||
/// Get a list of commands from a file. Does the work of ensuring the commands
|
||||
/// are syntactically valid.
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ note: inside `<CoroutineIteratorAdapter<{static coroutine@tests/fail/coroutine-p
|
|||
|
|
||||
LL | match me.resume(()) {
|
||||
| ^^^^^^^^^^^^^
|
||||
= note: inside `<std::boxed::Box<CoroutineIteratorAdapter<{static coroutine@tests/fail/coroutine-pinned-moved.rs:LL:CC}>> as std::iter::Iterator>::next` at RUSTLIB/alloc/src/boxed.rs:LL:CC
|
||||
= note: inside `std::boxed::iter::<impl std::iter::Iterator for std::boxed::Box<CoroutineIteratorAdapter<{static coroutine@tests/fail/coroutine-pinned-moved.rs:LL:CC}>>>::next` at RUSTLIB/alloc/src/boxed/iter.rs:LL:CC
|
||||
note: inside `main`
|
||||
--> tests/fail/coroutine-pinned-moved.rs:LL:CC
|
||||
|
|
||||
|
|
|
|||
|
|
@ -13,3 +13,6 @@ gimli = "0.31.0"
|
|||
build_helper = { path = "../build_helper" }
|
||||
serde_json = "1.0"
|
||||
libc = "0.2"
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib", "dylib"]
|
||||
|
|
|
|||
|
|
@ -222,6 +222,12 @@ pub struct CompletedProcess {
|
|||
}
|
||||
|
||||
impl CompletedProcess {
|
||||
#[must_use]
|
||||
#[track_caller]
|
||||
pub fn stdout(&self) -> Vec<u8> {
|
||||
self.output.stdout.clone()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[track_caller]
|
||||
pub fn stdout_utf8(&self) -> String {
|
||||
|
|
@ -234,12 +240,24 @@ impl CompletedProcess {
|
|||
String::from_utf8_lossy(&self.output.stdout.clone()).to_string()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[track_caller]
|
||||
pub fn stderr(&self) -> Vec<u8> {
|
||||
self.output.stderr.clone()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[track_caller]
|
||||
pub fn stderr_utf8(&self) -> String {
|
||||
String::from_utf8(self.output.stderr.clone()).expect("stderr is not valid UTF-8")
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[track_caller]
|
||||
pub fn invalid_stderr_utf8(&self) -> String {
|
||||
String::from_utf8_lossy(&self.output.stderr.clone()).to_string()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn status(&self) -> ExitStatus {
|
||||
self.output.status
|
||||
|
|
|
|||
|
|
@ -60,6 +60,18 @@ pub fn llvm_pdbutil() -> LlvmPdbutil {
|
|||
LlvmPdbutil::new()
|
||||
}
|
||||
|
||||
/// Construct a new `llvm-dis` invocation. This assumes that `llvm-dis` is available
|
||||
/// at `$LLVM_BIN_DIR/llvm-dis`.
|
||||
pub fn llvm_dis() -> LlvmDis {
|
||||
LlvmDis::new()
|
||||
}
|
||||
|
||||
/// Construct a new `llvm-objcopy` invocation. This assumes that `llvm-objcopy` is available
|
||||
/// at `$LLVM_BIN_DIR/llvm-objcopy`.
|
||||
pub fn llvm_objcopy() -> LlvmObjcopy {
|
||||
LlvmObjcopy::new()
|
||||
}
|
||||
|
||||
/// A `llvm-readobj` invocation builder.
|
||||
#[derive(Debug)]
|
||||
#[must_use]
|
||||
|
|
@ -123,6 +135,20 @@ pub struct LlvmPdbutil {
|
|||
cmd: Command,
|
||||
}
|
||||
|
||||
/// A `llvm-dis` invocation builder.
|
||||
#[derive(Debug)]
|
||||
#[must_use]
|
||||
pub struct LlvmDis {
|
||||
cmd: Command,
|
||||
}
|
||||
|
||||
/// A `llvm-objcopy` invocation builder.
|
||||
#[derive(Debug)]
|
||||
#[must_use]
|
||||
pub struct LlvmObjcopy {
|
||||
cmd: Command,
|
||||
}
|
||||
|
||||
crate::macros::impl_common_helpers!(LlvmReadobj);
|
||||
crate::macros::impl_common_helpers!(LlvmProfdata);
|
||||
crate::macros::impl_common_helpers!(LlvmFilecheck);
|
||||
|
|
@ -132,6 +158,8 @@ crate::macros::impl_common_helpers!(LlvmNm);
|
|||
crate::macros::impl_common_helpers!(LlvmBcanalyzer);
|
||||
crate::macros::impl_common_helpers!(LlvmDwarfdump);
|
||||
crate::macros::impl_common_helpers!(LlvmPdbutil);
|
||||
crate::macros::impl_common_helpers!(LlvmDis);
|
||||
crate::macros::impl_common_helpers!(LlvmObjcopy);
|
||||
|
||||
/// Generate the path to the bin directory of LLVM.
|
||||
#[must_use]
|
||||
|
|
@ -390,3 +418,41 @@ impl LlvmPdbutil {
|
|||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl LlvmObjcopy {
|
||||
/// Construct a new `llvm-objcopy` invocation. This assumes that `llvm-objcopy` is available
|
||||
/// at `$LLVM_BIN_DIR/llvm-objcopy`.
|
||||
pub fn new() -> Self {
|
||||
let llvm_objcopy = llvm_bin_dir().join("llvm-objcopy");
|
||||
let cmd = Command::new(llvm_objcopy);
|
||||
Self { cmd }
|
||||
}
|
||||
|
||||
/// Dump the contents of `section` into the file at `path`.
|
||||
#[track_caller]
|
||||
pub fn dump_section<S: AsRef<str>, P: AsRef<Path>>(
|
||||
&mut self,
|
||||
section_name: S,
|
||||
path: P,
|
||||
) -> &mut Self {
|
||||
self.cmd.arg("--dump-section");
|
||||
self.cmd.arg(format!("{}={}", section_name.as_ref(), path.as_ref().to_str().unwrap()));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl LlvmDis {
|
||||
/// Construct a new `llvm-dis` invocation. This assumes that `llvm-dis` is available
|
||||
/// at `$LLVM_BIN_DIR/llvm-dis`.
|
||||
pub fn new() -> Self {
|
||||
let llvm_dis = llvm_bin_dir().join("llvm-dis");
|
||||
let cmd = Command::new(llvm_dis);
|
||||
Self { cmd }
|
||||
}
|
||||
|
||||
/// Provide an input file.
|
||||
pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
|
||||
self.cmd.arg(path.as_ref());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,14 +49,17 @@ pub use external_deps::{c_build, cc, clang, htmldocck, llvm, python, rustc, rust
|
|||
|
||||
// These rely on external dependencies.
|
||||
pub use cc::{cc, cxx, extra_c_flags, extra_cxx_flags, Cc};
|
||||
pub use c_build::{build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_optimized, build_native_static_lib_cxx};
|
||||
pub use c_build::{
|
||||
build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_cxx,
|
||||
build_native_static_lib_optimized,
|
||||
};
|
||||
pub use cargo::cargo;
|
||||
pub use clang::{clang, Clang};
|
||||
pub use htmldocck::htmldocck;
|
||||
pub use llvm::{
|
||||
llvm_ar, llvm_bcanalyzer, llvm_dwarfdump, llvm_filecheck, llvm_nm, llvm_objdump, llvm_profdata,
|
||||
llvm_readobj, LlvmAr, LlvmBcanalyzer, LlvmDwarfdump, LlvmFilecheck, LlvmNm, LlvmObjdump,
|
||||
LlvmProfdata, LlvmReadobj,
|
||||
llvm_ar, llvm_bcanalyzer, llvm_dis, llvm_dwarfdump, llvm_filecheck, llvm_nm, llvm_objcopy,
|
||||
llvm_objdump, llvm_profdata, llvm_readobj, LlvmAr, LlvmBcanalyzer, LlvmDis, LlvmDwarfdump,
|
||||
LlvmFilecheck, LlvmNm, LlvmObjcopy, LlvmObjdump, LlvmProfdata, LlvmReadobj,
|
||||
};
|
||||
pub use python::python_command;
|
||||
pub use rustc::{aux_build, bare_rustc, rustc, rustc_path, Rustc};
|
||||
|
|
|
|||
|
|
@ -13,5 +13,5 @@ max_line_length = 100
|
|||
[*.md]
|
||||
indent_size = 2
|
||||
|
||||
[*.{yml, yaml}]
|
||||
[*.{yml,yaml}]
|
||||
indent_size = 2
|
||||
|
|
|
|||
|
|
@ -1,14 +1,10 @@
|
|||
# Please make sure that the `needs` fields for both `end-success` and `end-failure`
|
||||
# Please make sure that the `needs` field for the `conclusion` job
|
||||
# are updated when adding new jobs!
|
||||
|
||||
name: CI
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- auto
|
||||
- try
|
||||
- automation/bors/try
|
||||
merge_group:
|
||||
|
||||
env:
|
||||
CARGO_INCREMENTAL: 0
|
||||
|
|
@ -104,11 +100,11 @@ jobs:
|
|||
if: matrix.os == 'ubuntu-latest'
|
||||
run: target/${{ matrix.target }}/debug/rust-analyzer analysis-stats .
|
||||
|
||||
- name: Run analysis-stats on rust std library
|
||||
- name: Run analysis-stats on the rust standard libraries
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
env:
|
||||
RUSTC_BOOTSTRAP: 1
|
||||
run: target/${{ matrix.target }}/debug/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std
|
||||
RUSTC_BOOTSTRAP: 1
|
||||
run: target/${{ matrix.target }}/debug/rust-analyzer analysis-stats --with-deps --no-sysroot --no-test $(rustc --print sysroot)/lib/rustlib/src/rust/library/
|
||||
|
||||
- name: clippy
|
||||
if: matrix.os == 'windows-latest'
|
||||
|
|
@ -237,20 +233,21 @@ jobs:
|
|||
- name: check for typos
|
||||
run: typos
|
||||
|
||||
end-success:
|
||||
name: bors build finished
|
||||
if: github.event.pusher.name == 'bors' && success()
|
||||
runs-on: ubuntu-latest
|
||||
conclusion:
|
||||
needs: [rust, rust-cross, typescript, typo-check]
|
||||
steps:
|
||||
- name: Mark the job as successful
|
||||
run: exit 0
|
||||
|
||||
end-failure:
|
||||
name: bors build finished
|
||||
if: github.event.pusher.name == 'bors' && !success()
|
||||
# We need to ensure this job does *not* get skipped if its dependencies fail,
|
||||
# because a skipped job is considered a success by GitHub. So we have to
|
||||
# overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
|
||||
# when the workflow is canceled manually.
|
||||
#
|
||||
# ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
|
||||
if: ${{ !cancelled() }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: [rust, rust-cross, typescript, typo-check]
|
||||
steps:
|
||||
- name: Mark the job as a failure
|
||||
run: exit 1
|
||||
# Manually check the status of all dependencies. `if: failure()` does not work.
|
||||
- name: Conclusion
|
||||
run: |
|
||||
# Print the dependent jobs to see them in the CI log
|
||||
jq -C <<< '${{ toJson(needs) }}'
|
||||
# Check if all jobs that we depend on (in the needs array) were successful.
|
||||
jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
|
||||
|
|
|
|||
3
src/tools/rust-analyzer/.gitignore
vendored
3
src/tools/rust-analyzer/.gitignore
vendored
|
|
@ -1,6 +1,5 @@
|
|||
/target/
|
||||
target/
|
||||
/dist/
|
||||
crates/*/target
|
||||
**/*.rs.bk
|
||||
**/*.rs.pending-snap
|
||||
.idea/*
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ dependencies = [
|
|||
"intern",
|
||||
"la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lz4_flex",
|
||||
"rustc-hash",
|
||||
"rustc-hash 2.0.0",
|
||||
"salsa",
|
||||
"semver",
|
||||
"span",
|
||||
|
|
@ -161,9 +161,10 @@ dependencies = [
|
|||
"expect-test",
|
||||
"intern",
|
||||
"oorandom",
|
||||
"rustc-hash",
|
||||
"rustc-hash 2.0.0",
|
||||
"syntax",
|
||||
"syntax-bridge",
|
||||
"tracing",
|
||||
"tt",
|
||||
]
|
||||
|
||||
|
|
@ -216,7 +217,7 @@ dependencies = [
|
|||
"chalk-derive",
|
||||
"chalk-ir",
|
||||
"chalk-solve",
|
||||
"rustc-hash",
|
||||
"rustc-hash 1.1.0",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
|
|
@ -232,7 +233,7 @@ dependencies = [
|
|||
"indexmap",
|
||||
"itertools",
|
||||
"petgraph",
|
||||
"rustc-hash",
|
||||
"rustc-hash 1.1.0",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
|
|
@ -513,7 +514,7 @@ dependencies = [
|
|||
"hir-ty",
|
||||
"intern",
|
||||
"itertools",
|
||||
"rustc-hash",
|
||||
"rustc-hash 2.0.0",
|
||||
"smallvec",
|
||||
"span",
|
||||
"stdx",
|
||||
|
|
@ -547,7 +548,7 @@ dependencies = [
|
|||
"mbe",
|
||||
"ra-ap-rustc_abi",
|
||||
"ra-ap-rustc_parse_format",
|
||||
"rustc-hash",
|
||||
"rustc-hash 2.0.0",
|
||||
"rustc_apfloat",
|
||||
"smallvec",
|
||||
"span",
|
||||
|
|
@ -556,6 +557,7 @@ dependencies = [
|
|||
"syntax-bridge",
|
||||
"test-fixture",
|
||||
"test-utils",
|
||||
"text-size",
|
||||
"tracing",
|
||||
"triomphe",
|
||||
"tt",
|
||||
|
|
@ -577,7 +579,7 @@ dependencies = [
|
|||
"limit",
|
||||
"mbe",
|
||||
"parser",
|
||||
"rustc-hash",
|
||||
"rustc-hash 2.0.0",
|
||||
"smallvec",
|
||||
"span",
|
||||
"stdx",
|
||||
|
|
@ -616,7 +618,7 @@ dependencies = [
|
|||
"ra-ap-rustc_abi",
|
||||
"ra-ap-rustc_index",
|
||||
"ra-ap-rustc_pattern_analysis",
|
||||
"rustc-hash",
|
||||
"rustc-hash 2.0.0",
|
||||
"rustc_apfloat",
|
||||
"scoped-tls",
|
||||
"smallvec",
|
||||
|
|
@ -670,7 +672,6 @@ dependencies = [
|
|||
"syntax",
|
||||
"test-fixture",
|
||||
"test-utils",
|
||||
"text-edit",
|
||||
"toolchain",
|
||||
"tracing",
|
||||
"triomphe",
|
||||
|
|
@ -692,7 +693,6 @@ dependencies = [
|
|||
"syntax",
|
||||
"test-fixture",
|
||||
"test-utils",
|
||||
"text-edit",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
|
|
@ -711,7 +711,6 @@ dependencies = [
|
|||
"syntax",
|
||||
"test-fixture",
|
||||
"test-utils",
|
||||
"text-edit",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
|
|
@ -731,19 +730,18 @@ dependencies = [
|
|||
"indexmap",
|
||||
"itertools",
|
||||
"limit",
|
||||
"line-index 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"line-index 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr",
|
||||
"nohash-hasher",
|
||||
"parser",
|
||||
"profile",
|
||||
"rayon",
|
||||
"rustc-hash",
|
||||
"rustc-hash 2.0.0",
|
||||
"span",
|
||||
"stdx",
|
||||
"syntax",
|
||||
"test-fixture",
|
||||
"test-utils",
|
||||
"text-edit",
|
||||
"tracing",
|
||||
"triomphe",
|
||||
]
|
||||
|
|
@ -765,7 +763,6 @@ dependencies = [
|
|||
"syntax",
|
||||
"test-fixture",
|
||||
"test-utils",
|
||||
"text-edit",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
|
|
@ -784,7 +781,6 @@ dependencies = [
|
|||
"syntax",
|
||||
"test-fixture",
|
||||
"test-utils",
|
||||
"text-edit",
|
||||
"triomphe",
|
||||
]
|
||||
|
||||
|
|
@ -834,7 +830,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"dashmap",
|
||||
"hashbrown",
|
||||
"rustc-hash",
|
||||
"rustc-hash 2.0.0",
|
||||
"sptr",
|
||||
"triomphe",
|
||||
]
|
||||
|
|
@ -939,7 +935,7 @@ version = "0.0.0"
|
|||
|
||||
[[package]]
|
||||
name = "line-index"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"nohash-hasher",
|
||||
"oorandom",
|
||||
|
|
@ -948,9 +944,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "line-index"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67d61795376ae2683928c218fda7d7d7db136fd38c06b7552904667f0d55580a"
|
||||
checksum = "3e27e0ed5a392a7f5ba0b3808a2afccff16c64933312c84b57618b49d1209bd2"
|
||||
dependencies = [
|
||||
"nohash-hasher",
|
||||
"text-size",
|
||||
|
|
@ -1051,7 +1047,7 @@ dependencies = [
|
|||
"intern",
|
||||
"parser",
|
||||
"ra-ap-rustc_lexer",
|
||||
"rustc-hash",
|
||||
"rustc-hash 2.0.0",
|
||||
"smallvec",
|
||||
"span",
|
||||
"stdx",
|
||||
|
|
@ -1345,7 +1341,7 @@ dependencies = [
|
|||
"indexmap",
|
||||
"intern",
|
||||
"paths",
|
||||
"rustc-hash",
|
||||
"rustc-hash 2.0.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"span",
|
||||
|
|
@ -1435,7 +1431,7 @@ dependencies = [
|
|||
"itertools",
|
||||
"la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"paths",
|
||||
"rustc-hash",
|
||||
"rustc-hash 2.0.0",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -1497,9 +1493,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ra-ap-rustc_abi"
|
||||
version = "0.71.0"
|
||||
version = "0.75.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6999d098000b98415939f13158dac78cb3eeeb7b0c073847f3e4b623866e27c"
|
||||
checksum = "d5bc2cfc7264d84215a08875ef90a1d35f76b5c9ad1993515d2da7e4e40b2b4b"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"ra-ap-rustc_index",
|
||||
|
|
@ -1508,9 +1504,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ra-ap-rustc_index"
|
||||
version = "0.71.0"
|
||||
version = "0.75.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae9fb312d942817dab10790881f555928c1f6a11a85186e8e573ad4a86c7d3be"
|
||||
checksum = "e8929140697812e5dd09e19cf446d85146332363f0dbc125d4214834c34ead96"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"ra-ap-rustc_index_macros",
|
||||
|
|
@ -1519,9 +1515,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ra-ap-rustc_index_macros"
|
||||
version = "0.71.0"
|
||||
version = "0.75.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "766e3990eb1066a06deefc561b5a01b32ca5c9211feea31cbf4ed50611519872"
|
||||
checksum = "514a3f5d04c8b4a2750f29746cc9abb1f78deb7e72e4ad1dc95bbc608f3db157"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -1530,9 +1526,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ra-ap-rustc_lexer"
|
||||
version = "0.71.0"
|
||||
version = "0.75.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4afa98eb7889c137d5a3f1cd189089e16da04d1e4837d358a67aa3dab10ffbe"
|
||||
checksum = "276fcb1205da071a0cd64416f3f0e198043c11f176c5b501a45dbf0cb33979f2"
|
||||
dependencies = [
|
||||
"unicode-properties",
|
||||
"unicode-xid",
|
||||
|
|
@ -1540,9 +1536,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ra-ap-rustc_parse_format"
|
||||
version = "0.71.0"
|
||||
version = "0.75.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9234c96ffb0565286790407fb7eb7f55ebf69267de4db382fdec0a17f14b0e2"
|
||||
checksum = "961b30b22cfac296b14b72e9f95e79c16cebc8c926872755fb1568a6c4243a62"
|
||||
dependencies = [
|
||||
"ra-ap-rustc_index",
|
||||
"ra-ap-rustc_lexer",
|
||||
|
|
@ -1550,12 +1546,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ra-ap-rustc_pattern_analysis"
|
||||
version = "0.71.0"
|
||||
version = "0.75.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "273d5f72926a58c7eea27aebc898d1d5b32d23d2342f692a94a2cf8746aa4a2f"
|
||||
checksum = "614232513814a4b714fea7f11345d31c0c277bca3089bb6ca1ec20870bfc022a"
|
||||
dependencies = [
|
||||
"ra-ap-rustc_index",
|
||||
"rustc-hash",
|
||||
"rustc-hash 2.0.0",
|
||||
"rustc_apfloat",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
|
|
@ -1640,7 +1636,7 @@ dependencies = [
|
|||
"countme",
|
||||
"hashbrown",
|
||||
"memoffset",
|
||||
"rustc-hash",
|
||||
"rustc-hash 1.1.0",
|
||||
"text-size",
|
||||
]
|
||||
|
||||
|
|
@ -1680,7 +1676,7 @@ dependencies = [
|
|||
"profile",
|
||||
"project-model",
|
||||
"rayon",
|
||||
"rustc-hash",
|
||||
"rustc-hash 2.0.0",
|
||||
"scip",
|
||||
"semver",
|
||||
"serde",
|
||||
|
|
@ -1717,6 +1713,12 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_apfloat"
|
||||
version = "0.2.1+llvm-462a31f5a5ab"
|
||||
|
|
@ -1746,7 +1748,7 @@ dependencies = [
|
|||
"oorandom",
|
||||
"parking_lot",
|
||||
"rand",
|
||||
"rustc-hash",
|
||||
"rustc-hash 2.0.0",
|
||||
"salsa-macros",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
|
|
@ -1878,9 +1880,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
|||
|
||||
[[package]]
|
||||
name = "smol_str"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66eaf762c5af19db3108300515c8aa7a50efc90ff745f4c62288052ebf9fdd25"
|
||||
checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d"
|
||||
dependencies = [
|
||||
"borsh",
|
||||
"serde",
|
||||
|
|
@ -1898,7 +1900,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"hashbrown",
|
||||
"la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hash",
|
||||
"rustc-hash 2.0.0",
|
||||
"salsa",
|
||||
"stdx",
|
||||
"syntax",
|
||||
|
|
@ -1967,12 +1969,11 @@ dependencies = [
|
|||
"ra-ap-rustc_lexer",
|
||||
"rayon",
|
||||
"rowan",
|
||||
"rustc-hash",
|
||||
"rustc-hash 2.0.0",
|
||||
"rustc_apfloat",
|
||||
"smol_str",
|
||||
"stdx",
|
||||
"test-utils",
|
||||
"text-edit",
|
||||
"tracing",
|
||||
"triomphe",
|
||||
]
|
||||
|
|
@ -1983,7 +1984,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"intern",
|
||||
"parser",
|
||||
"rustc-hash",
|
||||
"rustc-hash 2.0.0",
|
||||
"span",
|
||||
"stdx",
|
||||
"syntax",
|
||||
|
|
@ -2000,7 +2001,7 @@ dependencies = [
|
|||
"cfg",
|
||||
"hir-expand",
|
||||
"intern",
|
||||
"rustc-hash",
|
||||
"rustc-hash 2.0.0",
|
||||
"span",
|
||||
"stdx",
|
||||
"test-utils",
|
||||
|
|
@ -2014,20 +2015,12 @@ dependencies = [
|
|||
"dissimilar",
|
||||
"paths",
|
||||
"profile",
|
||||
"rustc-hash",
|
||||
"rustc-hash 2.0.0",
|
||||
"stdx",
|
||||
"text-size",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "text-edit"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"text-size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "text-size"
|
||||
version = "1.1.1"
|
||||
|
|
@ -2361,7 +2354,7 @@ dependencies = [
|
|||
"indexmap",
|
||||
"nohash-hasher",
|
||||
"paths",
|
||||
"rustc-hash",
|
||||
"rustc-hash 2.0.0",
|
||||
"stdx",
|
||||
"tracing",
|
||||
]
|
||||
|
|
@ -2374,7 +2367,7 @@ dependencies = [
|
|||
"notify",
|
||||
"paths",
|
||||
"rayon",
|
||||
"rustc-hash",
|
||||
"rustc-hash 2.0.0",
|
||||
"stdx",
|
||||
"tracing",
|
||||
"vfs",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ exclude = ["crates/proc-macro-srv/proc-macro-test/imp"]
|
|||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
rust-version = "1.81"
|
||||
rust-version = "1.82"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
authors = ["rust-analyzer team"]
|
||||
|
|
@ -79,24 +79,23 @@ span = { path = "./crates/span", version = "0.0.0" }
|
|||
stdx = { path = "./crates/stdx", version = "0.0.0" }
|
||||
syntax = { path = "./crates/syntax", version = "0.0.0" }
|
||||
syntax-bridge = { path = "./crates/syntax-bridge", version = "0.0.0" }
|
||||
text-edit = { path = "./crates/text-edit", version = "0.0.0" }
|
||||
toolchain = { path = "./crates/toolchain", version = "0.0.0" }
|
||||
tt = { path = "./crates/tt", version = "0.0.0" }
|
||||
vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
|
||||
vfs = { path = "./crates/vfs", version = "0.0.0" }
|
||||
|
||||
ra-ap-rustc_lexer = { version = "0.71.0", default-features = false }
|
||||
ra-ap-rustc_parse_format = { version = "0.71.0", default-features = false }
|
||||
ra-ap-rustc_index = { version = "0.71.0", default-features = false }
|
||||
ra-ap-rustc_abi = { version = "0.71.0", default-features = false }
|
||||
ra-ap-rustc_pattern_analysis = { version = "0.71.0", default-features = false }
|
||||
ra-ap-rustc_lexer = { version = "0.75", default-features = false }
|
||||
ra-ap-rustc_parse_format = { version = "0.75", default-features = false }
|
||||
ra-ap-rustc_index = { version = "0.75", default-features = false }
|
||||
ra-ap-rustc_abi = { version = "0.75", default-features = false }
|
||||
ra-ap-rustc_pattern_analysis = { version = "0.75", default-features = false }
|
||||
|
||||
# local crates that aren't published to crates.io. These should not have versions.
|
||||
test-fixture = { path = "./crates/test-fixture" }
|
||||
test-utils = { path = "./crates/test-utils" }
|
||||
|
||||
# In-tree crates that are published separately and follow semver. See lib/README.md
|
||||
line-index = { version = "0.1.1" }
|
||||
line-index = { version = "0.1.2" }
|
||||
la-arena = { version = "0.3.1" }
|
||||
lsp-server = { version = "0.7.6" }
|
||||
|
||||
|
|
@ -136,7 +135,7 @@ process-wrap = { version = "8.0.2", features = ["std"] }
|
|||
pulldown-cmark-to-cmark = "10.0.4"
|
||||
pulldown-cmark = { version = "0.9.0", default-features = false }
|
||||
rayon = "1.8.0"
|
||||
rustc-hash = "1.1.0"
|
||||
rustc-hash = "2.0.0"
|
||||
semver = "1.0.14"
|
||||
serde = { version = "1.0.192", features = ["derive"] }
|
||||
serde_json = "1.0.108"
|
||||
|
|
@ -145,7 +144,7 @@ smallvec = { version = "1.10.0", features = [
|
|||
"union",
|
||||
"const_generics",
|
||||
] }
|
||||
smol_str = "0.3.1"
|
||||
smol_str = "0.3.2"
|
||||
snap = "1.1.0"
|
||||
text-size = "1.1.1"
|
||||
tracing = "0.1.40"
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ doctest = false
|
|||
|
||||
[dependencies]
|
||||
rustc-hash.workspace = true
|
||||
tracing.workspace = true
|
||||
|
||||
# locals deps
|
||||
tt = { workspace = true, optional = true }
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use std::fmt;
|
|||
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use intern::Symbol;
|
||||
use intern::{sym, Symbol};
|
||||
|
||||
pub use cfg_expr::{CfgAtom, CfgExpr};
|
||||
pub use dnf::DnfExpr;
|
||||
|
|
@ -24,11 +24,17 @@ pub use dnf::DnfExpr;
|
|||
/// of key and value in `key_values`.
|
||||
///
|
||||
/// See: <https://doc.rust-lang.org/reference/conditional-compilation.html#set-configuration-options>
|
||||
#[derive(Clone, PartialEq, Eq, Default)]
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct CfgOptions {
|
||||
enabled: FxHashSet<CfgAtom>,
|
||||
}
|
||||
|
||||
impl Default for CfgOptions {
|
||||
fn default() -> Self {
|
||||
Self { enabled: FxHashSet::from_iter([CfgAtom::Flag(sym::true_.clone())]) }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for CfgOptions {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut items = self
|
||||
|
|
@ -54,23 +60,37 @@ impl CfgOptions {
|
|||
}
|
||||
|
||||
pub fn insert_atom(&mut self, key: Symbol) {
|
||||
self.enabled.insert(CfgAtom::Flag(key));
|
||||
self.insert_any_atom(CfgAtom::Flag(key));
|
||||
}
|
||||
|
||||
pub fn insert_key_value(&mut self, key: Symbol, value: Symbol) {
|
||||
self.enabled.insert(CfgAtom::KeyValue { key, value });
|
||||
self.insert_any_atom(CfgAtom::KeyValue { key, value });
|
||||
}
|
||||
|
||||
pub fn apply_diff(&mut self, diff: CfgDiff) {
|
||||
for atom in diff.enable {
|
||||
self.enabled.insert(atom);
|
||||
self.insert_any_atom(atom);
|
||||
}
|
||||
|
||||
for atom in diff.disable {
|
||||
let (CfgAtom::Flag(sym) | CfgAtom::KeyValue { key: sym, .. }) = &atom;
|
||||
if *sym == sym::true_ || *sym == sym::false_ {
|
||||
tracing::error!("cannot remove `true` or `false` from cfg");
|
||||
continue;
|
||||
}
|
||||
self.enabled.remove(&atom);
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_any_atom(&mut self, atom: CfgAtom) {
|
||||
let (CfgAtom::Flag(sym) | CfgAtom::KeyValue { key: sym, .. }) = &atom;
|
||||
if *sym == sym::true_ || *sym == sym::false_ {
|
||||
tracing::error!("cannot insert `true` or `false` to cfg");
|
||||
return;
|
||||
}
|
||||
self.enabled.insert(atom);
|
||||
}
|
||||
|
||||
pub fn get_cfg_keys(&self) -> impl Iterator<Item = &Symbol> {
|
||||
self.enabled.iter().map(|it| match it {
|
||||
CfgAtom::Flag(key) => key,
|
||||
|
|
@ -88,7 +108,7 @@ impl CfgOptions {
|
|||
|
||||
impl Extend<CfgAtom> for CfgOptions {
|
||||
fn extend<T: IntoIterator<Item = CfgAtom>>(&mut self, iter: T) {
|
||||
iter.into_iter().for_each(|cfg_flag| _ = self.enabled.insert(cfg_flag));
|
||||
iter.into_iter().for_each(|cfg_flag| self.insert_any_atom(cfg_flag));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ smallvec.workspace = true
|
|||
hashbrown.workspace = true
|
||||
triomphe.workspace = true
|
||||
rustc_apfloat = "0.2.0"
|
||||
text-size.workspace = true
|
||||
|
||||
ra-ap-rustc_parse_format.workspace = true
|
||||
ra-ap-rustc_abi.workspace = true
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use std::ops::{Deref, Index};
|
|||
|
||||
use base_db::CrateId;
|
||||
use cfg::{CfgExpr, CfgOptions};
|
||||
use either::Either;
|
||||
use hir_expand::{name::Name, ExpandError, InFile};
|
||||
use la_arena::{Arena, ArenaMap, Idx, RawIdx};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
|
@ -22,15 +23,33 @@ use crate::{
|
|||
db::DefDatabase,
|
||||
expander::Expander,
|
||||
hir::{
|
||||
dummy_expr_id, Binding, BindingId, Expr, ExprId, Label, LabelId, Pat, PatId, RecordFieldPat,
|
||||
dummy_expr_id, Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, Label,
|
||||
LabelId, Pat, PatId, RecordFieldPat, Statement,
|
||||
},
|
||||
item_tree::AttrOwner,
|
||||
nameres::DefMap,
|
||||
path::{ModPath, Path},
|
||||
src::HasSource,
|
||||
type_ref::{TypeRef, TypeRefId, TypesMap, TypesSourceMap},
|
||||
BlockId, DefWithBodyId, HasModule, Lookup,
|
||||
};
|
||||
|
||||
/// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct HygieneId(pub(crate) span::SyntaxContextId);
|
||||
|
||||
impl HygieneId {
|
||||
pub const ROOT: Self = Self(span::SyntaxContextId::ROOT);
|
||||
|
||||
pub fn new(ctx: span::SyntaxContextId) -> Self {
|
||||
Self(ctx)
|
||||
}
|
||||
|
||||
pub(crate) fn is_root(self) -> bool {
|
||||
self.0.is_root()
|
||||
}
|
||||
}
|
||||
|
||||
/// The body of an item (function, const etc.).
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct Body {
|
||||
|
|
@ -51,8 +70,25 @@ pub struct Body {
|
|||
pub self_param: Option<BindingId>,
|
||||
/// The `ExprId` of the actual body expression.
|
||||
pub body_expr: ExprId,
|
||||
pub types: TypesMap,
|
||||
/// Block expressions in this body that may contain inner items.
|
||||
block_scopes: Vec<BlockId>,
|
||||
|
||||
/// A map from binding to its hygiene ID.
|
||||
///
|
||||
/// Bindings that don't come from macro expansion are not allocated to save space, so not all bindings appear here.
|
||||
/// If a binding does not appear here it has `SyntaxContextId::ROOT`.
|
||||
///
|
||||
/// Note that this may not be the direct `SyntaxContextId` of the binding's expansion, because transparent
|
||||
/// expansions are attributed to their parent expansion (recursively).
|
||||
binding_hygiene: FxHashMap<BindingId, HygieneId>,
|
||||
/// A map from an variable usages to their hygiene ID.
|
||||
///
|
||||
/// Expressions that can be recorded here are single segment path, although not all single segments path refer
|
||||
/// to variables and have hygiene (some refer to items, we don't know at this stage).
|
||||
expr_hygiene: FxHashMap<ExprId, HygieneId>,
|
||||
/// A map from a destructuring assignment possible variable usages to their hygiene ID.
|
||||
pat_hygiene: FxHashMap<PatId, HygieneId>,
|
||||
}
|
||||
|
||||
pub type ExprPtr = AstPtr<ast::Expr>;
|
||||
|
|
@ -67,9 +103,12 @@ pub type LabelSource = InFile<LabelPtr>;
|
|||
pub type FieldPtr = AstPtr<ast::RecordExprField>;
|
||||
pub type FieldSource = InFile<FieldPtr>;
|
||||
|
||||
pub type PatFieldPtr = AstPtr<ast::RecordPatField>;
|
||||
pub type PatFieldPtr = AstPtr<Either<ast::RecordExprField, ast::RecordPatField>>;
|
||||
pub type PatFieldSource = InFile<PatFieldPtr>;
|
||||
|
||||
pub type ExprOrPatPtr = AstPtr<Either<ast::Expr, ast::Pat>>;
|
||||
pub type ExprOrPatSource = InFile<ExprOrPatPtr>;
|
||||
|
||||
/// An item body together with the mapping from syntax nodes to HIR expression
|
||||
/// IDs. This is needed to go from e.g. a position in a file to the HIR
|
||||
/// expression containing it; but for type inference etc., we want to operate on
|
||||
|
|
@ -83,11 +122,13 @@ pub type PatFieldSource = InFile<PatFieldPtr>;
|
|||
/// this properly for macros.
|
||||
#[derive(Default, Debug, Eq, PartialEq)]
|
||||
pub struct BodySourceMap {
|
||||
expr_map: FxHashMap<ExprSource, ExprId>,
|
||||
// AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map
|
||||
// to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected).
|
||||
expr_map: FxHashMap<ExprSource, ExprOrPatId>,
|
||||
expr_map_back: ArenaMap<ExprId, ExprSource>,
|
||||
|
||||
pat_map: FxHashMap<PatSource, PatId>,
|
||||
pat_map_back: ArenaMap<PatId, PatSource>,
|
||||
pat_map_back: ArenaMap<PatId, ExprOrPatSource>,
|
||||
|
||||
label_map: FxHashMap<LabelSource, LabelId>,
|
||||
label_map_back: ArenaMap<LabelId, LabelSource>,
|
||||
|
|
@ -100,10 +141,13 @@ pub struct BodySourceMap {
|
|||
field_map_back: FxHashMap<ExprId, FieldSource>,
|
||||
pat_field_map_back: FxHashMap<PatId, PatFieldSource>,
|
||||
|
||||
types: TypesSourceMap,
|
||||
|
||||
// FIXME: Make this a sane struct.
|
||||
template_map: Option<
|
||||
Box<(
|
||||
// format_args!
|
||||
FxHashMap<ExprId, Vec<(syntax::TextRange, Name)>>,
|
||||
FxHashMap<ExprId, (HygieneId, Vec<(syntax::TextRange, Name)>)>,
|
||||
// asm!
|
||||
FxHashMap<ExprId, Vec<Vec<(syntax::TextRange, usize)>>>,
|
||||
)>,
|
||||
|
|
@ -261,6 +305,10 @@ impl Body {
|
|||
pats,
|
||||
bindings,
|
||||
binding_owners,
|
||||
binding_hygiene,
|
||||
expr_hygiene,
|
||||
pat_hygiene,
|
||||
types,
|
||||
} = self;
|
||||
block_scopes.shrink_to_fit();
|
||||
exprs.shrink_to_fit();
|
||||
|
|
@ -268,6 +316,10 @@ impl Body {
|
|||
pats.shrink_to_fit();
|
||||
bindings.shrink_to_fit();
|
||||
binding_owners.shrink_to_fit();
|
||||
binding_hygiene.shrink_to_fit();
|
||||
expr_hygiene.shrink_to_fit();
|
||||
pat_hygiene.shrink_to_fit();
|
||||
types.shrink_to_fit();
|
||||
}
|
||||
|
||||
pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) {
|
||||
|
|
@ -286,7 +338,8 @@ impl Body {
|
|||
| Pat::Path(..)
|
||||
| Pat::ConstBlock(..)
|
||||
| Pat::Wild
|
||||
| Pat::Missing => {}
|
||||
| Pat::Missing
|
||||
| Pat::Expr(_) => {}
|
||||
&Pat::Bind { subpat, .. } => {
|
||||
if let Some(subpat) = subpat {
|
||||
f(subpat);
|
||||
|
|
@ -322,6 +375,162 @@ impl Body {
|
|||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_child_exprs(&self, expr_id: ExprId, mut f: impl FnMut(ExprId)) {
|
||||
let expr = &self[expr_id];
|
||||
match expr {
|
||||
Expr::Continue { .. }
|
||||
| Expr::Const(_)
|
||||
| Expr::Missing
|
||||
| Expr::Path(_)
|
||||
| Expr::OffsetOf(_)
|
||||
| Expr::Literal(_)
|
||||
| Expr::Underscore => {}
|
||||
Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op {
|
||||
AsmOperand::In { expr, .. }
|
||||
| AsmOperand::Out { expr: Some(expr), .. }
|
||||
| AsmOperand::InOut { expr, .. } => f(*expr),
|
||||
AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
|
||||
f(*in_expr);
|
||||
if let Some(out_expr) = out_expr {
|
||||
f(*out_expr);
|
||||
}
|
||||
}
|
||||
AsmOperand::Out { expr: None, .. }
|
||||
| AsmOperand::Const(_)
|
||||
| AsmOperand::Label(_)
|
||||
| AsmOperand::Sym(_) => (),
|
||||
}),
|
||||
Expr::If { condition, then_branch, else_branch } => {
|
||||
f(*condition);
|
||||
f(*then_branch);
|
||||
if let &Some(else_branch) = else_branch {
|
||||
f(else_branch);
|
||||
}
|
||||
}
|
||||
Expr::Let { expr, .. } => {
|
||||
f(*expr);
|
||||
}
|
||||
Expr::Block { statements, tail, .. }
|
||||
| Expr::Unsafe { statements, tail, .. }
|
||||
| Expr::Async { statements, tail, .. } => {
|
||||
for stmt in statements.iter() {
|
||||
match stmt {
|
||||
Statement::Let { initializer, else_branch, pat, .. } => {
|
||||
if let &Some(expr) = initializer {
|
||||
f(expr);
|
||||
}
|
||||
if let &Some(expr) = else_branch {
|
||||
f(expr);
|
||||
}
|
||||
self.walk_exprs_in_pat(*pat, &mut f);
|
||||
}
|
||||
Statement::Expr { expr: expression, .. } => f(*expression),
|
||||
Statement::Item(_) => (),
|
||||
}
|
||||
}
|
||||
if let &Some(expr) = tail {
|
||||
f(expr);
|
||||
}
|
||||
}
|
||||
Expr::Loop { body, .. } => f(*body),
|
||||
Expr::Call { callee, args, .. } => {
|
||||
f(*callee);
|
||||
args.iter().copied().for_each(f);
|
||||
}
|
||||
Expr::MethodCall { receiver, args, .. } => {
|
||||
f(*receiver);
|
||||
args.iter().copied().for_each(f);
|
||||
}
|
||||
Expr::Match { expr, arms } => {
|
||||
f(*expr);
|
||||
arms.iter().map(|arm| arm.expr).for_each(f);
|
||||
}
|
||||
Expr::Break { expr, .. }
|
||||
| Expr::Return { expr }
|
||||
| Expr::Yield { expr }
|
||||
| Expr::Yeet { expr } => {
|
||||
if let &Some(expr) = expr {
|
||||
f(expr);
|
||||
}
|
||||
}
|
||||
Expr::Become { expr } => f(*expr),
|
||||
Expr::RecordLit { fields, spread, .. } => {
|
||||
for field in fields.iter() {
|
||||
f(field.expr);
|
||||
}
|
||||
if let &Some(expr) = spread {
|
||||
f(expr);
|
||||
}
|
||||
}
|
||||
Expr::Closure { body, .. } => {
|
||||
f(*body);
|
||||
}
|
||||
Expr::BinaryOp { lhs, rhs, .. } => {
|
||||
f(*lhs);
|
||||
f(*rhs);
|
||||
}
|
||||
Expr::Range { lhs, rhs, .. } => {
|
||||
if let &Some(lhs) = rhs {
|
||||
f(lhs);
|
||||
}
|
||||
if let &Some(rhs) = lhs {
|
||||
f(rhs);
|
||||
}
|
||||
}
|
||||
Expr::Index { base, index, .. } => {
|
||||
f(*base);
|
||||
f(*index);
|
||||
}
|
||||
Expr::Field { expr, .. }
|
||||
| Expr::Await { expr }
|
||||
| Expr::Cast { expr, .. }
|
||||
| Expr::Ref { expr, .. }
|
||||
| Expr::UnaryOp { expr, .. }
|
||||
| Expr::Box { expr } => {
|
||||
f(*expr);
|
||||
}
|
||||
Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f),
|
||||
Expr::Array(a) => match a {
|
||||
Array::ElementList { elements, .. } => elements.iter().copied().for_each(f),
|
||||
Array::Repeat { initializer, repeat } => {
|
||||
f(*initializer);
|
||||
f(*repeat)
|
||||
}
|
||||
},
|
||||
&Expr::Assignment { target, value } => {
|
||||
self.walk_exprs_in_pat(target, &mut f);
|
||||
f(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_exprs_in_pat(&self, pat_id: PatId, f: &mut impl FnMut(ExprId)) {
|
||||
self.walk_pats(pat_id, &mut |pat| {
|
||||
if let Pat::Expr(expr) | Pat::ConstBlock(expr) = self[pat] {
|
||||
f(expr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn binding_hygiene(&self, binding: BindingId) -> HygieneId {
|
||||
self.binding_hygiene.get(&binding).copied().unwrap_or(HygieneId::ROOT)
|
||||
}
|
||||
|
||||
pub fn expr_path_hygiene(&self, expr: ExprId) -> HygieneId {
|
||||
self.expr_hygiene.get(&expr).copied().unwrap_or(HygieneId::ROOT)
|
||||
}
|
||||
|
||||
pub fn pat_path_hygiene(&self, pat: PatId) -> HygieneId {
|
||||
self.pat_hygiene.get(&pat).copied().unwrap_or(HygieneId::ROOT)
|
||||
}
|
||||
|
||||
pub fn expr_or_pat_path_hygiene(&self, id: ExprOrPatId) -> HygieneId {
|
||||
match id {
|
||||
ExprOrPatId::ExprId(id) => self.expr_path_hygiene(id),
|
||||
ExprOrPatId::PatId(id) => self.pat_path_hygiene(id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Body {
|
||||
|
|
@ -336,6 +545,10 @@ impl Default for Body {
|
|||
block_scopes: Default::default(),
|
||||
binding_owners: Default::default(),
|
||||
self_param: Default::default(),
|
||||
binding_hygiene: Default::default(),
|
||||
expr_hygiene: Default::default(),
|
||||
pat_hygiene: Default::default(),
|
||||
types: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -372,14 +585,29 @@ impl Index<BindingId> for Body {
|
|||
}
|
||||
}
|
||||
|
||||
impl Index<TypeRefId> for Body {
|
||||
type Output = TypeRef;
|
||||
|
||||
fn index(&self, b: TypeRefId) -> &TypeRef {
|
||||
&self.types[b]
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Change `node_` prefix to something more reasonable.
|
||||
// Perhaps `expr_syntax` and `expr_id`?
|
||||
impl BodySourceMap {
|
||||
pub fn expr_or_pat_syntax(&self, id: ExprOrPatId) -> Result<ExprOrPatSource, SyntheticSyntax> {
|
||||
match id {
|
||||
ExprOrPatId::ExprId(id) => self.expr_syntax(id).map(|it| it.map(AstPtr::wrap_left)),
|
||||
ExprOrPatId::PatId(id) => self.pat_syntax(id),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> {
|
||||
self.expr_map_back.get(expr).cloned().ok_or(SyntheticSyntax)
|
||||
}
|
||||
|
||||
pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> {
|
||||
pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprOrPatId> {
|
||||
let src = node.map(AstPtr::new);
|
||||
self.expr_map.get(&src).cloned()
|
||||
}
|
||||
|
|
@ -395,7 +623,7 @@ impl BodySourceMap {
|
|||
self.expansions.iter().map(|(&a, &b)| (a, b))
|
||||
}
|
||||
|
||||
pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> {
|
||||
pub fn pat_syntax(&self, pat: PatId) -> Result<ExprOrPatSource, SyntheticSyntax> {
|
||||
self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax)
|
||||
}
|
||||
|
||||
|
|
@ -428,7 +656,7 @@ impl BodySourceMap {
|
|||
self.pat_field_map_back[&pat]
|
||||
}
|
||||
|
||||
pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option<ExprId> {
|
||||
pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option<ExprOrPatId> {
|
||||
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::MacroExpr>).map(AstPtr::upcast);
|
||||
self.expr_map.get(&src).copied()
|
||||
}
|
||||
|
|
@ -442,9 +670,11 @@ impl BodySourceMap {
|
|||
pub fn implicit_format_args(
|
||||
&self,
|
||||
node: InFile<&ast::FormatArgsExpr>,
|
||||
) -> Option<&[(syntax::TextRange, Name)]> {
|
||||
) -> Option<(HygieneId, &[(syntax::TextRange, Name)])> {
|
||||
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
|
||||
self.template_map.as_ref()?.0.get(self.expr_map.get(&src)?).map(std::ops::Deref::deref)
|
||||
let (hygiene, names) =
|
||||
self.template_map.as_ref()?.0.get(&self.expr_map.get(&src)?.as_expr()?)?;
|
||||
Some((*hygiene, &**names))
|
||||
}
|
||||
|
||||
pub fn asm_template_args(
|
||||
|
|
@ -452,8 +682,8 @@ impl BodySourceMap {
|
|||
node: InFile<&ast::AsmExpr>,
|
||||
) -> Option<(ExprId, &[Vec<(syntax::TextRange, usize)>])> {
|
||||
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
|
||||
let expr = self.expr_map.get(&src)?;
|
||||
Some(*expr).zip(self.template_map.as_ref()?.1.get(expr).map(std::ops::Deref::deref))
|
||||
let expr = self.expr_map.get(&src)?.as_expr()?;
|
||||
Some(expr).zip(self.template_map.as_ref()?.1.get(&expr).map(std::ops::Deref::deref))
|
||||
}
|
||||
|
||||
/// Get a reference to the body source map's diagnostics.
|
||||
|
|
@ -476,6 +706,7 @@ impl BodySourceMap {
|
|||
template_map,
|
||||
diagnostics,
|
||||
binding_definitions,
|
||||
types,
|
||||
} = self;
|
||||
if let Some(template_map) = template_map {
|
||||
template_map.0.shrink_to_fit();
|
||||
|
|
@ -492,14 +723,6 @@ impl BodySourceMap {
|
|||
expansions.shrink_to_fit();
|
||||
diagnostics.shrink_to_fit();
|
||||
binding_definitions.shrink_to_fit();
|
||||
}
|
||||
|
||||
pub fn template_map(
|
||||
&self,
|
||||
) -> Option<&(
|
||||
FxHashMap<Idx<Expr>, Vec<(tt::TextRange, Name)>>,
|
||||
FxHashMap<Idx<Expr>, Vec<Vec<(tt::TextRange, usize)>>>,
|
||||
)> {
|
||||
self.template_map.as_deref()
|
||||
types.shrink_to_fit();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -158,9 +158,7 @@ impl ExprCollector<'_> {
|
|||
AsmOperand::Const(self.collect_expr_opt(c.expr()))
|
||||
}
|
||||
ast::AsmOperand::AsmSym(s) => {
|
||||
let Some(path) =
|
||||
s.path().and_then(|p| self.expander.parse_path(self.db, p))
|
||||
else {
|
||||
let Some(path) = s.path().and_then(|p| self.parse_path(p)) else {
|
||||
continue;
|
||||
};
|
||||
AsmOperand::Sym(path)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ use crate::{
|
|||
Statement,
|
||||
},
|
||||
pretty::{print_generic_args, print_path, print_type_ref},
|
||||
type_ref::TypeRef,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
|
@ -69,20 +68,20 @@ pub(super) fn print_body_hir(
|
|||
};
|
||||
if let DefWithBodyId::FunctionId(it) = owner {
|
||||
p.buf.push('(');
|
||||
let function_data = &db.function_data(it);
|
||||
let function_data = db.function_data(it);
|
||||
let (mut params, ret_type) = (function_data.params.iter(), &function_data.ret_type);
|
||||
if let Some(self_param) = body.self_param {
|
||||
p.print_binding(self_param);
|
||||
p.buf.push_str(": ");
|
||||
if let Some(ty) = params.next() {
|
||||
p.print_type_ref(ty);
|
||||
p.print_type_ref(*ty, &function_data.types_map);
|
||||
p.buf.push_str(", ");
|
||||
}
|
||||
}
|
||||
body.params.iter().zip(params).for_each(|(¶m, ty)| {
|
||||
p.print_pat(param);
|
||||
p.buf.push_str(": ");
|
||||
p.print_type_ref(ty);
|
||||
p.print_type_ref(*ty, &function_data.types_map);
|
||||
p.buf.push_str(", ");
|
||||
});
|
||||
// remove the last ", " in param list
|
||||
|
|
@ -92,7 +91,7 @@ pub(super) fn print_body_hir(
|
|||
p.buf.push(')');
|
||||
// return type
|
||||
p.buf.push_str(" -> ");
|
||||
p.print_type_ref(ret_type);
|
||||
p.print_type_ref(*ret_type, &function_data.types_map);
|
||||
p.buf.push(' ');
|
||||
}
|
||||
p.print_expr(body.body_expr);
|
||||
|
|
@ -242,7 +241,7 @@ impl Printer<'_> {
|
|||
Expr::InlineAsm(_) => w!(self, "builtin#asm(_)"),
|
||||
Expr::OffsetOf(offset_of) => {
|
||||
w!(self, "builtin#offset_of(");
|
||||
self.print_type_ref(&offset_of.container);
|
||||
self.print_type_ref(offset_of.container, &self.body.types);
|
||||
let edition = self.edition;
|
||||
w!(
|
||||
self,
|
||||
|
|
@ -277,7 +276,7 @@ impl Printer<'_> {
|
|||
w!(self, "loop ");
|
||||
self.print_expr(*body);
|
||||
}
|
||||
Expr::Call { callee, args, is_assignee_expr: _ } => {
|
||||
Expr::Call { callee, args } => {
|
||||
self.print_expr(*callee);
|
||||
w!(self, "(");
|
||||
if !args.is_empty() {
|
||||
|
|
@ -296,7 +295,7 @@ impl Printer<'_> {
|
|||
if let Some(args) = generic_args {
|
||||
w!(self, "::<");
|
||||
let edition = self.edition;
|
||||
print_generic_args(self.db, args, self, edition).unwrap();
|
||||
print_generic_args(self.db, args, &self.body.types, self, edition).unwrap();
|
||||
w!(self, ">");
|
||||
}
|
||||
w!(self, "(");
|
||||
|
|
@ -372,7 +371,7 @@ impl Printer<'_> {
|
|||
self.print_expr(*expr);
|
||||
}
|
||||
}
|
||||
Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr: _ } => {
|
||||
Expr::RecordLit { path, fields, spread } => {
|
||||
match path {
|
||||
Some(path) => self.print_path(path),
|
||||
None => w!(self, "<EFBFBD>"),
|
||||
|
|
@ -391,9 +390,6 @@ impl Printer<'_> {
|
|||
p.print_expr(*spread);
|
||||
wln!(p);
|
||||
}
|
||||
if *ellipsis {
|
||||
wln!(p, "..");
|
||||
}
|
||||
});
|
||||
w!(self, "}}");
|
||||
}
|
||||
|
|
@ -408,7 +404,7 @@ impl Printer<'_> {
|
|||
Expr::Cast { expr, type_ref } => {
|
||||
self.print_expr(*expr);
|
||||
w!(self, " as ");
|
||||
self.print_type_ref(type_ref);
|
||||
self.print_type_ref(*type_ref, &self.body.types);
|
||||
}
|
||||
Expr::Ref { expr, rawness, mutability } => {
|
||||
w!(self, "&");
|
||||
|
|
@ -466,7 +462,7 @@ impl Printer<'_> {
|
|||
w!(self, ") ");
|
||||
}
|
||||
}
|
||||
Expr::Index { base, index, is_assignee_expr: _ } => {
|
||||
Expr::Index { base, index } => {
|
||||
self.print_expr(*base);
|
||||
w!(self, "[");
|
||||
self.print_expr(*index);
|
||||
|
|
@ -496,18 +492,18 @@ impl Printer<'_> {
|
|||
self.print_pat(*pat);
|
||||
if let Some(ty) = ty {
|
||||
w!(self, ": ");
|
||||
self.print_type_ref(ty);
|
||||
self.print_type_ref(*ty, &self.body.types);
|
||||
}
|
||||
}
|
||||
w!(self, "|");
|
||||
if let Some(ret_ty) = ret_type {
|
||||
w!(self, " -> ");
|
||||
self.print_type_ref(ret_ty);
|
||||
self.print_type_ref(*ret_ty, &self.body.types);
|
||||
}
|
||||
self.whitespace();
|
||||
self.print_expr(*body);
|
||||
}
|
||||
Expr::Tuple { exprs, is_assignee_expr: _ } => {
|
||||
Expr::Tuple { exprs } => {
|
||||
w!(self, "(");
|
||||
for expr in exprs.iter() {
|
||||
self.print_expr(*expr);
|
||||
|
|
@ -519,7 +515,7 @@ impl Printer<'_> {
|
|||
w!(self, "[");
|
||||
if !matches!(arr, Array::ElementList { elements, .. } if elements.is_empty()) {
|
||||
self.indented(|p| match arr {
|
||||
Array::ElementList { elements, is_assignee_expr: _ } => {
|
||||
Array::ElementList { elements } => {
|
||||
for elem in elements.iter() {
|
||||
p.print_expr(*elem);
|
||||
w!(p, ", ");
|
||||
|
|
@ -551,6 +547,11 @@ impl Printer<'_> {
|
|||
Expr::Const(id) => {
|
||||
w!(self, "const {{ /* {id:?} */ }}");
|
||||
}
|
||||
&Expr::Assignment { target, value } => {
|
||||
self.print_pat(target);
|
||||
w!(self, " = ");
|
||||
self.print_expr(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -719,6 +720,9 @@ impl Printer<'_> {
|
|||
w!(self, "const ");
|
||||
self.print_expr(*c);
|
||||
}
|
||||
Pat::Expr(expr) => {
|
||||
self.print_expr(*expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -729,7 +733,7 @@ impl Printer<'_> {
|
|||
self.print_pat(*pat);
|
||||
if let Some(ty) = type_ref {
|
||||
w!(self, ": ");
|
||||
self.print_type_ref(ty);
|
||||
self.print_type_ref(*ty, &self.body.types);
|
||||
}
|
||||
if let Some(init) = initializer {
|
||||
w!(self, " = ");
|
||||
|
|
@ -748,7 +752,7 @@ impl Printer<'_> {
|
|||
}
|
||||
wln!(self);
|
||||
}
|
||||
Statement::Item => (),
|
||||
Statement::Item(_) => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -787,14 +791,14 @@ impl Printer<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn print_type_ref(&mut self, ty: &TypeRef) {
|
||||
fn print_type_ref(&mut self, ty: TypeRefId, map: &TypesMap) {
|
||||
let edition = self.edition;
|
||||
print_type_ref(self.db, ty, self, edition).unwrap();
|
||||
print_type_ref(self.db, ty, map, self, edition).unwrap();
|
||||
}
|
||||
|
||||
fn print_path(&mut self, path: &Path) {
|
||||
let edition = self.edition;
|
||||
print_path(self.db, path, self, edition).unwrap();
|
||||
print_path(self.db, path, &self.body.types, self, edition).unwrap();
|
||||
}
|
||||
|
||||
fn print_binding(&mut self, id: BindingId) {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
//! Name resolution for expressions.
|
||||
use hir_expand::name::Name;
|
||||
use hir_expand::{name::Name, MacroDefId};
|
||||
use la_arena::{Arena, ArenaMap, Idx, IdxRange, RawIdx};
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
body::Body,
|
||||
body::{Body, HygieneId},
|
||||
db::DefDatabase,
|
||||
hir::{Binding, BindingId, Expr, ExprId, LabelId, Pat, PatId, Statement},
|
||||
hir::{Binding, BindingId, Expr, ExprId, Item, LabelId, Pat, PatId, Statement},
|
||||
BlockId, ConstBlockId, DefWithBodyId,
|
||||
};
|
||||
|
||||
|
|
@ -22,6 +22,7 @@ pub struct ExprScopes {
|
|||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct ScopeEntry {
|
||||
name: Name,
|
||||
hygiene: HygieneId,
|
||||
binding: BindingId,
|
||||
}
|
||||
|
||||
|
|
@ -30,6 +31,10 @@ impl ScopeEntry {
|
|||
&self.name
|
||||
}
|
||||
|
||||
pub(crate) fn hygiene(&self) -> HygieneId {
|
||||
self.hygiene
|
||||
}
|
||||
|
||||
pub fn binding(&self) -> BindingId {
|
||||
self.binding
|
||||
}
|
||||
|
|
@ -40,6 +45,8 @@ pub struct ScopeData {
|
|||
parent: Option<ScopeId>,
|
||||
block: Option<BlockId>,
|
||||
label: Option<(LabelId, Name)>,
|
||||
// FIXME: We can compress this with an enum for this and `label`/`block` if memory usage matters.
|
||||
macro_def: Option<Box<MacroDefId>>,
|
||||
entries: IdxRange<ScopeEntry>,
|
||||
}
|
||||
|
||||
|
|
@ -62,6 +69,12 @@ impl ExprScopes {
|
|||
self.scopes[scope].block
|
||||
}
|
||||
|
||||
/// If `scope` refers to a macro def scope, returns the corresponding `MacroId`.
|
||||
#[allow(clippy::borrowed_box)] // If we return `&MacroDefId` we need to move it, this way we just clone the `Box`.
|
||||
pub fn macro_def(&self, scope: ScopeId) -> Option<&Box<MacroDefId>> {
|
||||
self.scopes[scope].macro_def.as_ref()
|
||||
}
|
||||
|
||||
/// If `scope` refers to a labeled expression scope, returns the corresponding `Label`.
|
||||
pub fn label(&self, scope: ScopeId) -> Option<(LabelId, Name)> {
|
||||
self.scopes[scope].label.clone()
|
||||
|
|
@ -102,7 +115,7 @@ impl ExprScopes {
|
|||
};
|
||||
let mut root = scopes.root_scope();
|
||||
if let Some(self_param) = body.self_param {
|
||||
scopes.add_bindings(body, root, self_param);
|
||||
scopes.add_bindings(body, root, self_param, body.binding_hygiene(self_param));
|
||||
}
|
||||
scopes.add_params_bindings(body, root, &body.params);
|
||||
compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root, resolve_const_block);
|
||||
|
|
@ -114,6 +127,7 @@ impl ExprScopes {
|
|||
parent: None,
|
||||
block: None,
|
||||
label: None,
|
||||
macro_def: None,
|
||||
entries: empty_entries(self.scope_entries.len()),
|
||||
})
|
||||
}
|
||||
|
|
@ -123,6 +137,7 @@ impl ExprScopes {
|
|||
parent: Some(parent),
|
||||
block: None,
|
||||
label: None,
|
||||
macro_def: None,
|
||||
entries: empty_entries(self.scope_entries.len()),
|
||||
})
|
||||
}
|
||||
|
|
@ -132,6 +147,7 @@ impl ExprScopes {
|
|||
parent: Some(parent),
|
||||
block: None,
|
||||
label,
|
||||
macro_def: None,
|
||||
entries: empty_entries(self.scope_entries.len()),
|
||||
})
|
||||
}
|
||||
|
|
@ -146,21 +162,38 @@ impl ExprScopes {
|
|||
parent: Some(parent),
|
||||
block,
|
||||
label,
|
||||
macro_def: None,
|
||||
entries: empty_entries(self.scope_entries.len()),
|
||||
})
|
||||
}
|
||||
|
||||
fn add_bindings(&mut self, body: &Body, scope: ScopeId, binding: BindingId) {
|
||||
fn new_macro_def_scope(&mut self, parent: ScopeId, macro_id: Box<MacroDefId>) -> ScopeId {
|
||||
self.scopes.alloc(ScopeData {
|
||||
parent: Some(parent),
|
||||
block: None,
|
||||
label: None,
|
||||
macro_def: Some(macro_id),
|
||||
entries: empty_entries(self.scope_entries.len()),
|
||||
})
|
||||
}
|
||||
|
||||
fn add_bindings(
|
||||
&mut self,
|
||||
body: &Body,
|
||||
scope: ScopeId,
|
||||
binding: BindingId,
|
||||
hygiene: HygieneId,
|
||||
) {
|
||||
let Binding { name, .. } = &body.bindings[binding];
|
||||
let entry = self.scope_entries.alloc(ScopeEntry { name: name.clone(), binding });
|
||||
let entry = self.scope_entries.alloc(ScopeEntry { name: name.clone(), binding, hygiene });
|
||||
self.scopes[scope].entries =
|
||||
IdxRange::new_inclusive(self.scopes[scope].entries.start()..=entry);
|
||||
}
|
||||
|
||||
fn add_pat_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
|
||||
let pattern = &body[pat];
|
||||
if let Pat::Bind { id, .. } = pattern {
|
||||
self.add_bindings(body, scope, *id);
|
||||
if let Pat::Bind { id, .. } = *pattern {
|
||||
self.add_bindings(body, scope, id, body.binding_hygiene(id));
|
||||
}
|
||||
|
||||
pattern.walk_child_pats(|pat| self.add_pat_bindings(body, scope, pat));
|
||||
|
|
@ -206,7 +239,10 @@ fn compute_block_scopes(
|
|||
Statement::Expr { expr, .. } => {
|
||||
compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block);
|
||||
}
|
||||
Statement::Item => (),
|
||||
Statement::Item(Item::MacroDef(macro_id)) => {
|
||||
*scope = scopes.new_macro_def_scope(*scope, macro_id.clone());
|
||||
}
|
||||
Statement::Item(Item::Other) => (),
|
||||
}
|
||||
}
|
||||
if let Some(expr) = tail {
|
||||
|
|
@ -282,7 +318,7 @@ fn compute_expr_scopes(
|
|||
*scope = scopes.new_scope(*scope);
|
||||
scopes.add_pat_bindings(body, *scope, pat);
|
||||
}
|
||||
e => e.walk_child_exprs(|e| compute_expr_scopes(scopes, e, scope)),
|
||||
_ => body.walk_child_exprs(expr, |e| compute_expr_scopes(scopes, e, scope)),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -333,6 +369,8 @@ mod tests {
|
|||
|
||||
let expr_id = source_map
|
||||
.node_expr(InFile { file_id: file_id.into(), value: &marker.into() })
|
||||
.unwrap()
|
||||
.as_expr()
|
||||
.unwrap();
|
||||
let scope = scopes.scope_for(expr_id);
|
||||
|
||||
|
|
@ -488,8 +526,11 @@ fn foo() {
|
|||
|
||||
let expr_scope = {
|
||||
let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap();
|
||||
let expr_id =
|
||||
source_map.node_expr(InFile { file_id: file_id.into(), value: &expr_ast }).unwrap();
|
||||
let expr_id = source_map
|
||||
.node_expr(InFile { file_id: file_id.into(), value: &expr_ast })
|
||||
.unwrap()
|
||||
.as_expr()
|
||||
.unwrap();
|
||||
scopes.scope_for(expr_id).unwrap()
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -370,3 +370,37 @@ fn f(a: i32, b: u32) -> String {
|
|||
}"#]]
|
||||
.assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn destructuring_assignment_tuple_macro() {
|
||||
// This is a funny one. `let m!()() = Bar()` is an error in rustc, because `m!()()` isn't a valid pattern,
|
||||
// but in destructuring assignment it is valid, because `m!()()` is a valid expression, and destructuring
|
||||
// assignments start their lives as expressions. So we have to do the same.
|
||||
|
||||
let (db, body, def) = lower(
|
||||
r#"
|
||||
struct Bar();
|
||||
|
||||
macro_rules! m {
|
||||
() => { Bar };
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
m!()() = Bar();
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
||||
let (_, source_map) = db.body_with_source_map(def);
|
||||
assert_eq!(source_map.diagnostics(), &[]);
|
||||
|
||||
for (_, def_map) in body.blocks(&db) {
|
||||
assert_eq!(def_map.diagnostics(), &[]);
|
||||
}
|
||||
|
||||
expect![[r#"
|
||||
fn foo() -> () {
|
||||
Bar() = Bar();
|
||||
}"#]]
|
||||
.assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use base_db::CrateId;
|
|||
use hir_expand::{
|
||||
name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefKind,
|
||||
};
|
||||
use intern::{sym, Interned, Symbol};
|
||||
use intern::{sym, Symbol};
|
||||
use la_arena::{Idx, RawIdx};
|
||||
use smallvec::SmallVec;
|
||||
use syntax::{ast, Parse};
|
||||
|
|
@ -25,7 +25,7 @@ use crate::{
|
|||
DefMap, MacroSubNs,
|
||||
},
|
||||
path::ImportAlias,
|
||||
type_ref::{TraitRef, TypeBound, TypeRef},
|
||||
type_ref::{TraitRef, TypeBound, TypeRefId, TypesMap},
|
||||
visibility::RawVisibility,
|
||||
AssocItemId, AstIdWithPath, ConstId, ConstLoc, ExternCrateId, FunctionId, FunctionLoc,
|
||||
HasModule, ImplId, Intern, ItemContainerId, ItemLoc, Lookup, Macro2Id, MacroRulesId, ModuleId,
|
||||
|
|
@ -35,13 +35,14 @@ use crate::{
|
|||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct FunctionData {
|
||||
pub name: Name,
|
||||
pub params: Box<[Interned<TypeRef>]>,
|
||||
pub ret_type: Interned<TypeRef>,
|
||||
pub params: Box<[TypeRefId]>,
|
||||
pub ret_type: TypeRefId,
|
||||
pub attrs: Attrs,
|
||||
pub visibility: RawVisibility,
|
||||
pub abi: Option<Symbol>,
|
||||
pub legacy_const_generics_indices: Option<Box<Box<[u32]>>>,
|
||||
pub rustc_allow_incoherent_impl: bool,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
flags: FnFlags,
|
||||
}
|
||||
|
||||
|
|
@ -110,13 +111,14 @@ impl FunctionData {
|
|||
.filter(|&(idx, _)| {
|
||||
item_tree.attrs(db, krate, attr_owner(idx)).is_cfg_enabled(cfg_options)
|
||||
})
|
||||
.filter_map(|(_, param)| param.type_ref.clone())
|
||||
.filter_map(|(_, param)| param.type_ref)
|
||||
.collect(),
|
||||
ret_type: func.ret_type.clone(),
|
||||
ret_type: func.ret_type,
|
||||
attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
|
||||
visibility,
|
||||
abi: func.abi.clone(),
|
||||
legacy_const_generics_indices,
|
||||
types_map: func.types_map.clone(),
|
||||
flags,
|
||||
rustc_allow_incoherent_impl,
|
||||
})
|
||||
|
|
@ -148,6 +150,10 @@ impl FunctionData {
|
|||
self.flags.contains(FnFlags::HAS_UNSAFE_KW)
|
||||
}
|
||||
|
||||
pub fn is_safe(&self) -> bool {
|
||||
self.flags.contains(FnFlags::HAS_SAFE_KW)
|
||||
}
|
||||
|
||||
pub fn is_varargs(&self) -> bool {
|
||||
self.flags.contains(FnFlags::IS_VARARGS)
|
||||
}
|
||||
|
|
@ -178,13 +184,14 @@ fn parse_rustc_legacy_const_generics(tt: &crate::tt::Subtree) -> Box<[u32]> {
|
|||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct TypeAliasData {
|
||||
pub name: Name,
|
||||
pub type_ref: Option<Interned<TypeRef>>,
|
||||
pub type_ref: Option<TypeRefId>,
|
||||
pub visibility: RawVisibility,
|
||||
pub is_extern: bool,
|
||||
pub rustc_has_incoherent_inherent_impls: bool,
|
||||
pub rustc_allow_incoherent_impl: bool,
|
||||
/// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
|
||||
pub bounds: Box<[Interned<TypeBound>]>,
|
||||
pub bounds: Box<[TypeBound]>,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
}
|
||||
|
||||
impl TypeAliasData {
|
||||
|
|
@ -212,12 +219,13 @@ impl TypeAliasData {
|
|||
|
||||
Arc::new(TypeAliasData {
|
||||
name: typ.name.clone(),
|
||||
type_ref: typ.type_ref.clone(),
|
||||
type_ref: typ.type_ref,
|
||||
visibility,
|
||||
is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
|
||||
rustc_has_incoherent_inherent_impls,
|
||||
rustc_allow_incoherent_impl,
|
||||
bounds: typ.bounds.clone(),
|
||||
types_map: typ.types_map.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -339,13 +347,14 @@ impl TraitAliasData {
|
|||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct ImplData {
|
||||
pub target_trait: Option<Interned<TraitRef>>,
|
||||
pub self_ty: Interned<TypeRef>,
|
||||
pub target_trait: Option<TraitRef>,
|
||||
pub self_ty: TypeRefId,
|
||||
pub items: Box<[AssocItemId]>,
|
||||
pub is_negative: bool,
|
||||
pub is_unsafe: bool,
|
||||
// box it as the vec is usually empty anyways
|
||||
pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
}
|
||||
|
||||
impl ImplData {
|
||||
|
|
@ -364,7 +373,7 @@ impl ImplData {
|
|||
let item_tree = tree_id.item_tree(db);
|
||||
let impl_def = &item_tree[tree_id.value];
|
||||
let target_trait = impl_def.target_trait.clone();
|
||||
let self_ty = impl_def.self_ty.clone();
|
||||
let self_ty = impl_def.self_ty;
|
||||
let is_negative = impl_def.is_negative;
|
||||
let is_unsafe = impl_def.is_unsafe;
|
||||
|
||||
|
|
@ -383,6 +392,7 @@ impl ImplData {
|
|||
is_negative,
|
||||
is_unsafe,
|
||||
macro_calls,
|
||||
types_map: impl_def.types_map.clone(),
|
||||
}),
|
||||
DefDiagnostics::new(diagnostics),
|
||||
)
|
||||
|
|
@ -528,10 +538,11 @@ impl ExternCrateDeclData {
|
|||
pub struct ConstData {
|
||||
/// `None` for `const _: () = ();`
|
||||
pub name: Option<Name>,
|
||||
pub type_ref: Interned<TypeRef>,
|
||||
pub type_ref: TypeRefId,
|
||||
pub visibility: RawVisibility,
|
||||
pub rustc_allow_incoherent_impl: bool,
|
||||
pub has_body: bool,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
}
|
||||
|
||||
impl ConstData {
|
||||
|
|
@ -552,10 +563,11 @@ impl ConstData {
|
|||
|
||||
Arc::new(ConstData {
|
||||
name: konst.name.clone(),
|
||||
type_ref: konst.type_ref.clone(),
|
||||
type_ref: konst.type_ref,
|
||||
visibility,
|
||||
rustc_allow_incoherent_impl,
|
||||
has_body: konst.has_body,
|
||||
types_map: konst.types_map.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -563,10 +575,13 @@ impl ConstData {
|
|||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct StaticData {
|
||||
pub name: Name,
|
||||
pub type_ref: Interned<TypeRef>,
|
||||
pub type_ref: TypeRefId,
|
||||
pub visibility: RawVisibility,
|
||||
pub mutable: bool,
|
||||
pub is_extern: bool,
|
||||
pub has_safe_kw: bool,
|
||||
pub has_unsafe_kw: bool,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
}
|
||||
|
||||
impl StaticData {
|
||||
|
|
@ -577,10 +592,13 @@ impl StaticData {
|
|||
|
||||
Arc::new(StaticData {
|
||||
name: statik.name.clone(),
|
||||
type_ref: statik.type_ref.clone(),
|
||||
type_ref: statik.type_ref,
|
||||
visibility: item_tree[statik.visibility].clone(),
|
||||
mutable: statik.mutable,
|
||||
is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
|
||||
has_safe_kw: statik.has_safe_kw,
|
||||
has_unsafe_kw: statik.has_unsafe_kw,
|
||||
types_map: statik.types_map.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use cfg::CfgOptions;
|
|||
use either::Either;
|
||||
|
||||
use hir_expand::name::Name;
|
||||
use intern::{sym, Interned};
|
||||
use intern::sym;
|
||||
use la_arena::Arena;
|
||||
use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions};
|
||||
use triomphe::Arc;
|
||||
|
|
@ -21,7 +21,7 @@ use crate::{
|
|||
lang_item::LangItem,
|
||||
nameres::diagnostics::{DefDiagnostic, DefDiagnostics},
|
||||
tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree},
|
||||
type_ref::TypeRef,
|
||||
type_ref::{TypeRefId, TypesMap},
|
||||
visibility::RawVisibility,
|
||||
EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId, VariantId,
|
||||
};
|
||||
|
|
@ -73,8 +73,8 @@ pub struct EnumVariantData {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum VariantData {
|
||||
Record(Arena<FieldData>),
|
||||
Tuple(Arena<FieldData>),
|
||||
Record { fields: Arena<FieldData>, types_map: Arc<TypesMap> },
|
||||
Tuple { fields: Arena<FieldData>, types_map: Arc<TypesMap> },
|
||||
Unit,
|
||||
}
|
||||
|
||||
|
|
@ -82,7 +82,7 @@ pub enum VariantData {
|
|||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct FieldData {
|
||||
pub name: Name,
|
||||
pub type_ref: Interned<TypeRef>,
|
||||
pub type_ref: TypeRefId,
|
||||
pub visibility: RawVisibility,
|
||||
}
|
||||
|
||||
|
|
@ -208,7 +208,7 @@ impl StructData {
|
|||
}
|
||||
|
||||
let strukt = &item_tree[loc.id.value];
|
||||
let (data, diagnostics) = lower_fields(
|
||||
let (fields, diagnostics) = lower_fields(
|
||||
db,
|
||||
krate,
|
||||
loc.container.local_id,
|
||||
|
|
@ -219,12 +219,13 @@ impl StructData {
|
|||
&strukt.fields,
|
||||
None,
|
||||
);
|
||||
let types_map = strukt.types_map.clone();
|
||||
(
|
||||
Arc::new(StructData {
|
||||
name: strukt.name.clone(),
|
||||
variant_data: Arc::new(match strukt.shape {
|
||||
FieldsShape::Record => VariantData::Record(data),
|
||||
FieldsShape::Tuple => VariantData::Tuple(data),
|
||||
FieldsShape::Record => VariantData::Record { fields, types_map },
|
||||
FieldsShape::Tuple => VariantData::Tuple { fields, types_map },
|
||||
FieldsShape::Unit => VariantData::Unit,
|
||||
}),
|
||||
repr,
|
||||
|
|
@ -258,7 +259,7 @@ impl StructData {
|
|||
}
|
||||
|
||||
let union = &item_tree[loc.id.value];
|
||||
let (data, diagnostics) = lower_fields(
|
||||
let (fields, diagnostics) = lower_fields(
|
||||
db,
|
||||
krate,
|
||||
loc.container.local_id,
|
||||
|
|
@ -269,10 +270,11 @@ impl StructData {
|
|||
&union.fields,
|
||||
None,
|
||||
);
|
||||
let types_map = union.types_map.clone();
|
||||
(
|
||||
Arc::new(StructData {
|
||||
name: union.name.clone(),
|
||||
variant_data: Arc::new(VariantData::Record(data)),
|
||||
variant_data: Arc::new(VariantData::Record { fields, types_map }),
|
||||
repr,
|
||||
visibility: item_tree[union.visibility].clone(),
|
||||
flags,
|
||||
|
|
@ -360,7 +362,7 @@ impl EnumVariantData {
|
|||
let item_tree = loc.id.item_tree(db);
|
||||
let variant = &item_tree[loc.id.value];
|
||||
|
||||
let (data, diagnostics) = lower_fields(
|
||||
let (fields, diagnostics) = lower_fields(
|
||||
db,
|
||||
krate,
|
||||
container.local_id,
|
||||
|
|
@ -371,13 +373,14 @@ impl EnumVariantData {
|
|||
&variant.fields,
|
||||
Some(item_tree[loc.parent.lookup(db).id.value].visibility),
|
||||
);
|
||||
let types_map = variant.types_map.clone();
|
||||
|
||||
(
|
||||
Arc::new(EnumVariantData {
|
||||
name: variant.name.clone(),
|
||||
variant_data: Arc::new(match variant.shape {
|
||||
FieldsShape::Record => VariantData::Record(data),
|
||||
FieldsShape::Tuple => VariantData::Tuple(data),
|
||||
FieldsShape::Record => VariantData::Record { fields, types_map },
|
||||
FieldsShape::Tuple => VariantData::Tuple { fields, types_map },
|
||||
FieldsShape::Unit => VariantData::Unit,
|
||||
}),
|
||||
}),
|
||||
|
|
@ -390,11 +393,20 @@ impl VariantData {
|
|||
pub fn fields(&self) -> &Arena<FieldData> {
|
||||
const EMPTY: &Arena<FieldData> = &Arena::new();
|
||||
match &self {
|
||||
VariantData::Record(fields) | VariantData::Tuple(fields) => fields,
|
||||
VariantData::Record { fields, .. } | VariantData::Tuple { fields, .. } => fields,
|
||||
_ => EMPTY,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn types_map(&self) -> &TypesMap {
|
||||
match &self {
|
||||
VariantData::Record { types_map, .. } | VariantData::Tuple { types_map, .. } => {
|
||||
types_map
|
||||
}
|
||||
VariantData::Unit => TypesMap::EMPTY,
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Linear lookup
|
||||
pub fn field(&self, name: &Name) -> Option<LocalFieldId> {
|
||||
self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None })
|
||||
|
|
@ -402,8 +414,8 @@ impl VariantData {
|
|||
|
||||
pub fn kind(&self) -> StructKind {
|
||||
match self {
|
||||
VariantData::Record(_) => StructKind::Record,
|
||||
VariantData::Tuple(_) => StructKind::Tuple,
|
||||
VariantData::Record { .. } => StructKind::Record,
|
||||
VariantData::Tuple { .. } => StructKind::Tuple,
|
||||
VariantData::Unit => StructKind::Unit,
|
||||
}
|
||||
}
|
||||
|
|
@ -463,7 +475,7 @@ fn lower_field(
|
|||
) -> FieldData {
|
||||
FieldData {
|
||||
name: field.name.clone(),
|
||||
type_ref: field.type_ref.clone(),
|
||||
type_ref: field.type_ref,
|
||||
visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
use base_db::{ra_salsa, CrateId, SourceDatabase, Upcast};
|
||||
use either::Either;
|
||||
use hir_expand::{db::ExpandDatabase, HirFileId, MacroDefId};
|
||||
use intern::{sym, Interned};
|
||||
use intern::sym;
|
||||
use la_arena::ArenaMap;
|
||||
use span::{EditionedFileId, MacroCallId};
|
||||
use syntax::{ast, AstPtr};
|
||||
|
|
@ -18,9 +18,10 @@ use crate::{
|
|||
},
|
||||
generics::GenericParams,
|
||||
import_map::ImportMap,
|
||||
item_tree::{AttrOwner, ItemTree},
|
||||
item_tree::{AttrOwner, ItemTree, ItemTreeSourceMaps},
|
||||
lang_item::{self, LangItem, LangItemTarget, LangItems},
|
||||
nameres::{diagnostics::DefDiagnostics, DefMap},
|
||||
type_ref::TypesSourceMap,
|
||||
visibility::{self, Visibility},
|
||||
AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId,
|
||||
EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId,
|
||||
|
|
@ -91,6 +92,18 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
|
|||
#[ra_salsa::invoke(ItemTree::block_item_tree_query)]
|
||||
fn block_item_tree(&self, block_id: BlockId) -> Arc<ItemTree>;
|
||||
|
||||
#[ra_salsa::invoke(ItemTree::file_item_tree_with_source_map_query)]
|
||||
fn file_item_tree_with_source_map(
|
||||
&self,
|
||||
file_id: HirFileId,
|
||||
) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>);
|
||||
|
||||
#[ra_salsa::invoke(ItemTree::block_item_tree_with_source_map_query)]
|
||||
fn block_item_tree_with_source_map(
|
||||
&self,
|
||||
block_id: BlockId,
|
||||
) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>);
|
||||
|
||||
#[ra_salsa::invoke(DefMap::crate_def_map_query)]
|
||||
fn crate_def_map(&self, krate: CrateId) -> Arc<DefMap>;
|
||||
|
||||
|
|
@ -187,7 +200,14 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
|
|||
fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>;
|
||||
|
||||
#[ra_salsa::invoke(GenericParams::generic_params_query)]
|
||||
fn generic_params(&self, def: GenericDefId) -> Interned<GenericParams>;
|
||||
fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>;
|
||||
|
||||
/// If this returns `None` for the source map, that means it is the same as with the item tree.
|
||||
#[ra_salsa::invoke(GenericParams::generic_params_with_source_map_query)]
|
||||
fn generic_params_with_source_map(
|
||||
&self,
|
||||
def: GenericDefId,
|
||||
) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>);
|
||||
|
||||
// region:attrs
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use span::SyntaxContextId;
|
|||
use syntax::{ast, Parse};
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::type_ref::{TypesMap, TypesSourceMap};
|
||||
use crate::{
|
||||
attr::Attrs, db::DefDatabase, lower::LowerCtx, path::Path, AsMacroCall, MacroId, ModuleId,
|
||||
UnresolvedMacro,
|
||||
|
|
@ -49,6 +50,10 @@ impl Expander {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn span_map(&self, db: &dyn DefDatabase) -> &SpanMap {
|
||||
self.span_map.get_or_init(|| db.span_map(self.current_file_id))
|
||||
}
|
||||
|
||||
pub fn krate(&self) -> CrateId {
|
||||
self.module.krate
|
||||
}
|
||||
|
|
@ -110,8 +115,19 @@ impl Expander {
|
|||
mark.bomb.defuse();
|
||||
}
|
||||
|
||||
pub fn ctx<'a>(&self, db: &'a dyn DefDatabase) -> LowerCtx<'a> {
|
||||
LowerCtx::with_span_map_cell(db, self.current_file_id, self.span_map.clone())
|
||||
pub fn ctx<'a>(
|
||||
&self,
|
||||
db: &'a dyn DefDatabase,
|
||||
types_map: &'a mut TypesMap,
|
||||
types_source_map: &'a mut TypesSourceMap,
|
||||
) -> LowerCtx<'a> {
|
||||
LowerCtx::with_span_map_cell(
|
||||
db,
|
||||
self.current_file_id,
|
||||
self.span_map.clone(),
|
||||
types_map,
|
||||
types_source_map,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn in_file<T>(&self, value: T) -> InFile<T> {
|
||||
|
|
@ -138,8 +154,20 @@ impl Expander {
|
|||
self.current_file_id
|
||||
}
|
||||
|
||||
pub(crate) fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option<Path> {
|
||||
let ctx = LowerCtx::with_span_map_cell(db, self.current_file_id, self.span_map.clone());
|
||||
pub(crate) fn parse_path(
|
||||
&mut self,
|
||||
db: &dyn DefDatabase,
|
||||
path: ast::Path,
|
||||
types_map: &mut TypesMap,
|
||||
types_source_map: &mut TypesSourceMap,
|
||||
) -> Option<Path> {
|
||||
let ctx = LowerCtx::with_span_map_cell(
|
||||
db,
|
||||
self.current_file_id,
|
||||
self.span_map.clone(),
|
||||
types_map,
|
||||
types_source_map,
|
||||
);
|
||||
Path::from_src(&ctx, path)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1025,7 +1025,7 @@ pub mod ast {
|
|||
check_found_path(
|
||||
r#"
|
||||
mod bar {
|
||||
mod foo { pub(super) struct S; }
|
||||
mod foo { pub(crate) struct S; }
|
||||
pub(crate) use foo::*;
|
||||
}
|
||||
$0
|
||||
|
|
@ -1047,7 +1047,7 @@ $0
|
|||
check_found_path(
|
||||
r#"
|
||||
mod bar {
|
||||
mod foo { pub(super) struct S; }
|
||||
mod foo { pub(crate) struct S; }
|
||||
pub(crate) use foo::S as U;
|
||||
}
|
||||
$0
|
||||
|
|
|
|||
|
|
@ -3,16 +3,18 @@
|
|||
//! generic parameters. See also the `Generics` type and the `generics_of` query
|
||||
//! in rustc.
|
||||
|
||||
use std::ops;
|
||||
use std::{ops, sync::LazyLock};
|
||||
|
||||
use either::Either;
|
||||
use hir_expand::{
|
||||
name::{AsName, Name},
|
||||
ExpandResult,
|
||||
};
|
||||
use intern::Interned;
|
||||
use la_arena::{Arena, RawIdx};
|
||||
use stdx::impl_from;
|
||||
use stdx::{
|
||||
impl_from,
|
||||
thin_vec::{EmptyOptimizedThinVec, ThinVec},
|
||||
};
|
||||
use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds};
|
||||
use triomphe::Arc;
|
||||
|
||||
|
|
@ -22,7 +24,11 @@ use crate::{
|
|||
item_tree::{AttrOwner, FileItemTreeId, GenericModItem, GenericsItemTreeNode, ItemTree},
|
||||
lower::LowerCtx,
|
||||
nameres::{DefMap, MacroSubNs},
|
||||
type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
|
||||
path::{AssociatedTypeBinding, GenericArg, GenericArgs, NormalPath, Path},
|
||||
type_ref::{
|
||||
ArrayType, ConstRef, FnType, LifetimeRef, RefType, TypeBound, TypeRef, TypeRefId, TypesMap,
|
||||
TypesSourceMap,
|
||||
},
|
||||
AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LifetimeParamId,
|
||||
LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
|
||||
};
|
||||
|
|
@ -37,7 +43,7 @@ pub struct TypeParamData {
|
|||
/// [`None`] only if the type ref is an [`TypeRef::ImplTrait`]. FIXME: Might be better to just
|
||||
/// make it always be a value, giving impl trait a special name.
|
||||
pub name: Option<Name>,
|
||||
pub default: Option<Interned<TypeRef>>,
|
||||
pub default: Option<TypeRefId>,
|
||||
pub provenance: TypeParamProvenance,
|
||||
}
|
||||
|
||||
|
|
@ -51,7 +57,7 @@ pub struct LifetimeParamData {
|
|||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct ConstParamData {
|
||||
pub name: Name,
|
||||
pub ty: Interned<TypeRef>,
|
||||
pub ty: TypeRefId,
|
||||
pub default: Option<ConstRef>,
|
||||
}
|
||||
|
||||
|
|
@ -161,6 +167,7 @@ pub struct GenericParams {
|
|||
type_or_consts: Arena<TypeOrConstParamData>,
|
||||
lifetimes: Arena<LifetimeParamData>,
|
||||
where_predicates: Box<[WherePredicate]>,
|
||||
pub types_map: TypesMap,
|
||||
}
|
||||
|
||||
impl ops::Index<LocalTypeOrConstParamId> for GenericParams {
|
||||
|
|
@ -183,24 +190,14 @@ impl ops::Index<LocalLifetimeParamId> for GenericParams {
|
|||
/// associated type bindings like `Iterator<Item = u32>`.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum WherePredicate {
|
||||
TypeBound {
|
||||
target: WherePredicateTypeTarget,
|
||||
bound: Interned<TypeBound>,
|
||||
},
|
||||
Lifetime {
|
||||
target: LifetimeRef,
|
||||
bound: LifetimeRef,
|
||||
},
|
||||
ForLifetime {
|
||||
lifetimes: Box<[Name]>,
|
||||
target: WherePredicateTypeTarget,
|
||||
bound: Interned<TypeBound>,
|
||||
},
|
||||
TypeBound { target: WherePredicateTypeTarget, bound: TypeBound },
|
||||
Lifetime { target: LifetimeRef, bound: LifetimeRef },
|
||||
ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound },
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum WherePredicateTypeTarget {
|
||||
TypeRef(Interned<TypeRef>),
|
||||
TypeRef(TypeRefId),
|
||||
/// For desugared where predicates that can directly refer to a type param.
|
||||
TypeOrConstParam(LocalTypeOrConstParamId),
|
||||
}
|
||||
|
|
@ -300,7 +297,14 @@ impl GenericParams {
|
|||
pub(crate) fn generic_params_query(
|
||||
db: &dyn DefDatabase,
|
||||
def: GenericDefId,
|
||||
) -> Interned<GenericParams> {
|
||||
) -> Arc<GenericParams> {
|
||||
db.generic_params_with_source_map(def).0
|
||||
}
|
||||
|
||||
pub(crate) fn generic_params_with_source_map_query(
|
||||
db: &dyn DefDatabase,
|
||||
def: GenericDefId,
|
||||
) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>) {
|
||||
let _p = tracing::info_span!("generic_params_query").entered();
|
||||
|
||||
let krate = def.krate(db);
|
||||
|
|
@ -309,7 +313,7 @@ impl GenericParams {
|
|||
|
||||
// Returns the generic parameters that are enabled under the current `#[cfg]` options
|
||||
let enabled_params =
|
||||
|params: &Interned<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| {
|
||||
|params: &Arc<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| {
|
||||
let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
|
||||
let attr_owner_ct = |param| AttrOwner::TypeOrConstParamData(parent, param);
|
||||
let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param);
|
||||
|
|
@ -325,7 +329,7 @@ impl GenericParams {
|
|||
if all_type_or_consts_enabled && all_lifetimes_enabled {
|
||||
params.clone()
|
||||
} else {
|
||||
Interned::new(GenericParams {
|
||||
Arc::new(GenericParams {
|
||||
type_or_consts: all_type_or_consts_enabled
|
||||
.then(|| params.type_or_consts.clone())
|
||||
.unwrap_or_else(|| {
|
||||
|
|
@ -347,6 +351,7 @@ impl GenericParams {
|
|||
.collect()
|
||||
}),
|
||||
where_predicates: params.where_predicates.clone(),
|
||||
types_map: params.types_map.clone(),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
|
@ -357,18 +362,18 @@ impl GenericParams {
|
|||
Data = impl ItemTreeLoc<Id = Id>,
|
||||
>,
|
||||
enabled_params: impl Fn(
|
||||
&Interned<GenericParams>,
|
||||
&Arc<GenericParams>,
|
||||
&ItemTree,
|
||||
GenericModItem,
|
||||
) -> Interned<GenericParams>,
|
||||
) -> Interned<GenericParams>
|
||||
) -> Arc<GenericParams>,
|
||||
) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>)
|
||||
where
|
||||
FileItemTreeId<Id>: Into<GenericModItem>,
|
||||
{
|
||||
let id = id.lookup(db).item_tree_id();
|
||||
let tree = id.item_tree(db);
|
||||
let item = &tree[id.value];
|
||||
enabled_params(item.generic_params(), &tree, id.value.into())
|
||||
(enabled_params(item.generic_params(), &tree, id.value.into()), None)
|
||||
}
|
||||
|
||||
match def {
|
||||
|
|
@ -383,28 +388,37 @@ impl GenericParams {
|
|||
let module = loc.container.module(db);
|
||||
let func_data = db.function_data(id);
|
||||
if func_data.params.is_empty() {
|
||||
enabled_params
|
||||
(enabled_params, None)
|
||||
} else {
|
||||
let source_maps = loc.id.item_tree_with_source_map(db).1;
|
||||
let item_source_maps = source_maps.function(loc.id.value);
|
||||
let mut generic_params = GenericParamsCollector {
|
||||
type_or_consts: enabled_params.type_or_consts.clone(),
|
||||
lifetimes: enabled_params.lifetimes.clone(),
|
||||
where_predicates: enabled_params.where_predicates.clone().into(),
|
||||
};
|
||||
|
||||
let (mut types_map, mut types_source_maps) =
|
||||
(enabled_params.types_map.clone(), item_source_maps.generics().clone());
|
||||
// Don't create an `Expander` if not needed since this
|
||||
// could cause a reparse after the `ItemTree` has been created due to the spanmap.
|
||||
let mut expander = None;
|
||||
for param in func_data.params.iter() {
|
||||
for ¶m in func_data.params.iter() {
|
||||
generic_params.fill_implicit_impl_trait_args(
|
||||
db,
|
||||
&mut types_map,
|
||||
&mut types_source_maps,
|
||||
&mut expander,
|
||||
&mut || {
|
||||
(module.def_map(db), Expander::new(db, loc.id.file_id(), module))
|
||||
},
|
||||
param,
|
||||
&item.types_map,
|
||||
item_source_maps.item(),
|
||||
);
|
||||
}
|
||||
Interned::new(generic_params.finish())
|
||||
let generics = generic_params.finish(types_map, &mut types_source_maps);
|
||||
(generics, Some(Arc::new(types_source_maps)))
|
||||
}
|
||||
}
|
||||
GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics(db, id, enabled_params),
|
||||
|
|
@ -414,11 +428,15 @@ impl GenericParams {
|
|||
GenericDefId::TraitAliasId(id) => id_to_generics(db, id, enabled_params),
|
||||
GenericDefId::TypeAliasId(id) => id_to_generics(db, id, enabled_params),
|
||||
GenericDefId::ImplId(id) => id_to_generics(db, id, enabled_params),
|
||||
GenericDefId::ConstId(_) => Interned::new(GenericParams {
|
||||
type_or_consts: Default::default(),
|
||||
lifetimes: Default::default(),
|
||||
where_predicates: Default::default(),
|
||||
}),
|
||||
GenericDefId::ConstId(_) => (
|
||||
Arc::new(GenericParams {
|
||||
type_or_consts: Default::default(),
|
||||
lifetimes: Default::default(),
|
||||
where_predicates: Default::default(),
|
||||
types_map: Default::default(),
|
||||
}),
|
||||
None,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -452,7 +470,7 @@ impl GenericParamsCollector {
|
|||
&mut self,
|
||||
lower_ctx: &LowerCtx<'_>,
|
||||
type_bounds: Option<ast::TypeBoundList>,
|
||||
target: Either<TypeRef, LifetimeRef>,
|
||||
target: Either<TypeRefId, LifetimeRef>,
|
||||
) {
|
||||
for bound in type_bounds.iter().flat_map(|type_bound_list| type_bound_list.bounds()) {
|
||||
self.add_where_predicate_from_bound(lower_ctx, bound, None, target.clone());
|
||||
|
|
@ -473,16 +491,15 @@ impl GenericParamsCollector {
|
|||
ast::TypeOrConstParam::Type(type_param) => {
|
||||
let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
|
||||
// FIXME: Use `Path::from_src`
|
||||
let default = type_param
|
||||
.default_type()
|
||||
.map(|it| Interned::new(TypeRef::from_ast(lower_ctx, it)));
|
||||
let default =
|
||||
type_param.default_type().map(|it| TypeRef::from_ast(lower_ctx, it));
|
||||
let param = TypeParamData {
|
||||
name: Some(name.clone()),
|
||||
default,
|
||||
provenance: TypeParamProvenance::TypeParamList,
|
||||
};
|
||||
let idx = self.type_or_consts.alloc(param.into());
|
||||
let type_ref = TypeRef::Path(name.into());
|
||||
let type_ref = lower_ctx.alloc_type_ref_desugared(TypeRef::Path(name.into()));
|
||||
self.fill_bounds(
|
||||
lower_ctx,
|
||||
type_param.type_bound_list(),
|
||||
|
|
@ -492,12 +509,10 @@ impl GenericParamsCollector {
|
|||
}
|
||||
ast::TypeOrConstParam::Const(const_param) => {
|
||||
let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
|
||||
let ty = const_param
|
||||
.ty()
|
||||
.map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it));
|
||||
let ty = TypeRef::from_ast_opt(lower_ctx, const_param.ty());
|
||||
let param = ConstParamData {
|
||||
name,
|
||||
ty: Interned::new(ty),
|
||||
ty,
|
||||
default: ConstRef::from_const_param(lower_ctx, &const_param),
|
||||
};
|
||||
let idx = self.type_or_consts.alloc(param.into());
|
||||
|
|
@ -557,7 +572,7 @@ impl GenericParamsCollector {
|
|||
lower_ctx: &LowerCtx<'_>,
|
||||
bound: ast::TypeBound,
|
||||
hrtb_lifetimes: Option<&[Name]>,
|
||||
target: Either<TypeRef, LifetimeRef>,
|
||||
target: Either<TypeRefId, LifetimeRef>,
|
||||
) {
|
||||
let bound = TypeBound::from_ast(lower_ctx, bound);
|
||||
self.fill_impl_trait_bounds(lower_ctx.take_impl_traits_bounds());
|
||||
|
|
@ -565,12 +580,12 @@ impl GenericParamsCollector {
|
|||
(Either::Left(type_ref), bound) => match hrtb_lifetimes {
|
||||
Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
|
||||
lifetimes: hrtb_lifetimes.to_vec().into_boxed_slice(),
|
||||
target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
|
||||
bound: Interned::new(bound),
|
||||
target: WherePredicateTypeTarget::TypeRef(type_ref),
|
||||
bound,
|
||||
},
|
||||
None => WherePredicate::TypeBound {
|
||||
target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
|
||||
bound: Interned::new(bound),
|
||||
target: WherePredicateTypeTarget::TypeRef(type_ref),
|
||||
bound,
|
||||
},
|
||||
},
|
||||
(Either::Right(lifetime), TypeBound::Lifetime(bound)) => {
|
||||
|
|
@ -581,7 +596,7 @@ impl GenericParamsCollector {
|
|||
self.where_predicates.push(predicate);
|
||||
}
|
||||
|
||||
fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<Vec<Interned<TypeBound>>>) {
|
||||
fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<ThinVec<TypeBound>>) {
|
||||
for bounds in impl_bounds {
|
||||
let param = TypeParamData {
|
||||
name: None,
|
||||
|
|
@ -589,10 +604,10 @@ impl GenericParamsCollector {
|
|||
provenance: TypeParamProvenance::ArgumentImplTrait,
|
||||
};
|
||||
let param_id = self.type_or_consts.alloc(param.into());
|
||||
for bound in bounds {
|
||||
for bound in &bounds {
|
||||
self.where_predicates.push(WherePredicate::TypeBound {
|
||||
target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
|
||||
bound,
|
||||
bound: bound.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -601,12 +616,16 @@ impl GenericParamsCollector {
|
|||
fn fill_implicit_impl_trait_args(
|
||||
&mut self,
|
||||
db: &dyn DefDatabase,
|
||||
generics_types_map: &mut TypesMap,
|
||||
generics_types_source_map: &mut TypesSourceMap,
|
||||
// FIXME: Change this back to `LazyCell` if https://github.com/rust-lang/libs-team/issues/429 is accepted.
|
||||
exp: &mut Option<(Arc<DefMap>, Expander)>,
|
||||
exp_fill: &mut dyn FnMut() -> (Arc<DefMap>, Expander),
|
||||
type_ref: &TypeRef,
|
||||
type_ref: TypeRefId,
|
||||
types_map: &TypesMap,
|
||||
types_source_map: &TypesSourceMap,
|
||||
) {
|
||||
type_ref.walk(&mut |type_ref| {
|
||||
TypeRef::walk(type_ref, types_map, &mut |type_ref| {
|
||||
if let TypeRef::ImplTrait(bounds) = type_ref {
|
||||
let param = TypeParamData {
|
||||
name: None,
|
||||
|
|
@ -615,12 +634,20 @@ impl GenericParamsCollector {
|
|||
};
|
||||
let param_id = self.type_or_consts.alloc(param.into());
|
||||
for bound in bounds {
|
||||
let bound = copy_type_bound(
|
||||
bound,
|
||||
types_map,
|
||||
types_source_map,
|
||||
generics_types_map,
|
||||
generics_types_source_map,
|
||||
);
|
||||
self.where_predicates.push(WherePredicate::TypeBound {
|
||||
target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
|
||||
bound: bound.clone(),
|
||||
bound,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if let TypeRef::Macro(mc) = type_ref {
|
||||
let macro_call = mc.to_node(db.upcast());
|
||||
let (def_map, expander) = exp.get_or_insert_with(&mut *exp_fill);
|
||||
|
|
@ -641,23 +668,217 @@ impl GenericParamsCollector {
|
|||
if let Ok(ExpandResult { value: Some((mark, expanded)), .. }) =
|
||||
expander.enter_expand(db, macro_call, resolver)
|
||||
{
|
||||
let ctx = expander.ctx(db);
|
||||
let (mut macro_types_map, mut macro_types_source_map) =
|
||||
(TypesMap::default(), TypesSourceMap::default());
|
||||
let ctx = expander.ctx(db, &mut macro_types_map, &mut macro_types_source_map);
|
||||
let type_ref = TypeRef::from_ast(&ctx, expanded.tree());
|
||||
self.fill_implicit_impl_trait_args(db, &mut *exp, exp_fill, &type_ref);
|
||||
self.fill_implicit_impl_trait_args(
|
||||
db,
|
||||
generics_types_map,
|
||||
generics_types_source_map,
|
||||
&mut *exp,
|
||||
exp_fill,
|
||||
type_ref,
|
||||
¯o_types_map,
|
||||
¯o_types_source_map,
|
||||
);
|
||||
exp.get_or_insert_with(&mut *exp_fill).1.exit(mark);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn finish(self) -> GenericParams {
|
||||
let Self { mut lifetimes, mut type_or_consts, where_predicates } = self;
|
||||
pub(crate) fn finish(
|
||||
self,
|
||||
mut generics_types_map: TypesMap,
|
||||
generics_types_source_map: &mut TypesSourceMap,
|
||||
) -> Arc<GenericParams> {
|
||||
let Self { mut lifetimes, mut type_or_consts, mut where_predicates } = self;
|
||||
|
||||
if lifetimes.is_empty() && type_or_consts.is_empty() && where_predicates.is_empty() {
|
||||
static EMPTY: LazyLock<Arc<GenericParams>> = LazyLock::new(|| {
|
||||
Arc::new(GenericParams {
|
||||
lifetimes: Arena::new(),
|
||||
type_or_consts: Arena::new(),
|
||||
where_predicates: Box::default(),
|
||||
types_map: TypesMap::default(),
|
||||
})
|
||||
});
|
||||
return Arc::clone(&EMPTY);
|
||||
}
|
||||
|
||||
lifetimes.shrink_to_fit();
|
||||
type_or_consts.shrink_to_fit();
|
||||
GenericParams {
|
||||
where_predicates.shrink_to_fit();
|
||||
generics_types_map.shrink_to_fit();
|
||||
generics_types_source_map.shrink_to_fit();
|
||||
Arc::new(GenericParams {
|
||||
type_or_consts,
|
||||
lifetimes,
|
||||
where_predicates: where_predicates.into_boxed_slice(),
|
||||
}
|
||||
types_map: generics_types_map,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Copies a `TypeRef` from a `TypesMap` (accompanied with `TypesSourceMap`) into another `TypesMap`
|
||||
/// (and `TypesSourceMap`).
|
||||
fn copy_type_ref(
|
||||
type_ref: TypeRefId,
|
||||
from: &TypesMap,
|
||||
from_source_map: &TypesSourceMap,
|
||||
to: &mut TypesMap,
|
||||
to_source_map: &mut TypesSourceMap,
|
||||
) -> TypeRefId {
|
||||
let result = match &from[type_ref] {
|
||||
TypeRef::Fn(fn_) => {
|
||||
let params = fn_.params().iter().map(|(name, param_type)| {
|
||||
(name.clone(), copy_type_ref(*param_type, from, from_source_map, to, to_source_map))
|
||||
});
|
||||
TypeRef::Fn(FnType::new(fn_.is_varargs(), fn_.is_unsafe(), fn_.abi().clone(), params))
|
||||
}
|
||||
TypeRef::Tuple(types) => TypeRef::Tuple(EmptyOptimizedThinVec::from_iter(
|
||||
types.iter().map(|&t| copy_type_ref(t, from, from_source_map, to, to_source_map)),
|
||||
)),
|
||||
&TypeRef::RawPtr(type_ref, mutbl) => TypeRef::RawPtr(
|
||||
copy_type_ref(type_ref, from, from_source_map, to, to_source_map),
|
||||
mutbl,
|
||||
),
|
||||
TypeRef::Reference(ref_) => TypeRef::Reference(Box::new(RefType {
|
||||
ty: copy_type_ref(ref_.ty, from, from_source_map, to, to_source_map),
|
||||
lifetime: ref_.lifetime.clone(),
|
||||
mutability: ref_.mutability,
|
||||
})),
|
||||
TypeRef::Array(array) => TypeRef::Array(Box::new(ArrayType {
|
||||
ty: copy_type_ref(array.ty, from, from_source_map, to, to_source_map),
|
||||
len: array.len.clone(),
|
||||
})),
|
||||
&TypeRef::Slice(type_ref) => {
|
||||
TypeRef::Slice(copy_type_ref(type_ref, from, from_source_map, to, to_source_map))
|
||||
}
|
||||
TypeRef::ImplTrait(bounds) => TypeRef::ImplTrait(ThinVec::from_iter(copy_type_bounds(
|
||||
bounds,
|
||||
from,
|
||||
from_source_map,
|
||||
to,
|
||||
to_source_map,
|
||||
))),
|
||||
TypeRef::DynTrait(bounds) => TypeRef::DynTrait(ThinVec::from_iter(copy_type_bounds(
|
||||
bounds,
|
||||
from,
|
||||
from_source_map,
|
||||
to,
|
||||
to_source_map,
|
||||
))),
|
||||
TypeRef::Path(path) => {
|
||||
TypeRef::Path(copy_path(path, from, from_source_map, to, to_source_map))
|
||||
}
|
||||
TypeRef::Never => TypeRef::Never,
|
||||
TypeRef::Placeholder => TypeRef::Placeholder,
|
||||
TypeRef::Macro(macro_call) => TypeRef::Macro(*macro_call),
|
||||
TypeRef::Error => TypeRef::Error,
|
||||
};
|
||||
let id = to.types.alloc(result);
|
||||
if let Some(&ptr) = from_source_map.types_map_back.get(id) {
|
||||
to_source_map.types_map_back.insert(id, ptr);
|
||||
}
|
||||
id
|
||||
}
|
||||
|
||||
fn copy_path(
|
||||
path: &Path,
|
||||
from: &TypesMap,
|
||||
from_source_map: &TypesSourceMap,
|
||||
to: &mut TypesMap,
|
||||
to_source_map: &mut TypesSourceMap,
|
||||
) -> Path {
|
||||
match path {
|
||||
Path::BarePath(mod_path) => Path::BarePath(mod_path.clone()),
|
||||
Path::Normal(path) => {
|
||||
let type_anchor = path
|
||||
.type_anchor()
|
||||
.map(|type_ref| copy_type_ref(type_ref, from, from_source_map, to, to_source_map));
|
||||
let mod_path = path.mod_path().clone();
|
||||
let generic_args = path.generic_args().iter().map(|generic_args| {
|
||||
copy_generic_args(generic_args, from, from_source_map, to, to_source_map)
|
||||
});
|
||||
Path::Normal(NormalPath::new(type_anchor, mod_path, generic_args))
|
||||
}
|
||||
Path::LangItem(lang_item, name) => Path::LangItem(*lang_item, name.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
fn copy_generic_args(
|
||||
generic_args: &Option<GenericArgs>,
|
||||
from: &TypesMap,
|
||||
from_source_map: &TypesSourceMap,
|
||||
to: &mut TypesMap,
|
||||
to_source_map: &mut TypesSourceMap,
|
||||
) -> Option<GenericArgs> {
|
||||
generic_args.as_ref().map(|generic_args| {
|
||||
let args = generic_args
|
||||
.args
|
||||
.iter()
|
||||
.map(|arg| match arg {
|
||||
&GenericArg::Type(ty) => {
|
||||
GenericArg::Type(copy_type_ref(ty, from, from_source_map, to, to_source_map))
|
||||
}
|
||||
GenericArg::Lifetime(lifetime) => GenericArg::Lifetime(lifetime.clone()),
|
||||
GenericArg::Const(konst) => GenericArg::Const(konst.clone()),
|
||||
})
|
||||
.collect();
|
||||
let bindings = generic_args
|
||||
.bindings
|
||||
.iter()
|
||||
.map(|binding| {
|
||||
let name = binding.name.clone();
|
||||
let args =
|
||||
copy_generic_args(&binding.args, from, from_source_map, to, to_source_map);
|
||||
let type_ref = binding.type_ref.map(|type_ref| {
|
||||
copy_type_ref(type_ref, from, from_source_map, to, to_source_map)
|
||||
});
|
||||
let bounds =
|
||||
copy_type_bounds(&binding.bounds, from, from_source_map, to, to_source_map)
|
||||
.collect();
|
||||
AssociatedTypeBinding { name, args, type_ref, bounds }
|
||||
})
|
||||
.collect();
|
||||
GenericArgs {
|
||||
args,
|
||||
has_self_type: generic_args.has_self_type,
|
||||
bindings,
|
||||
desugared_from_fn: generic_args.desugared_from_fn,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn copy_type_bounds<'a>(
|
||||
bounds: &'a [TypeBound],
|
||||
from: &'a TypesMap,
|
||||
from_source_map: &'a TypesSourceMap,
|
||||
to: &'a mut TypesMap,
|
||||
to_source_map: &'a mut TypesSourceMap,
|
||||
) -> impl stdx::thin_vec::TrustedLen<Item = TypeBound> + 'a {
|
||||
bounds.iter().map(|bound| copy_type_bound(bound, from, from_source_map, to, to_source_map))
|
||||
}
|
||||
|
||||
fn copy_type_bound(
|
||||
bound: &TypeBound,
|
||||
from: &TypesMap,
|
||||
from_source_map: &TypesSourceMap,
|
||||
to: &mut TypesMap,
|
||||
to_source_map: &mut TypesSourceMap,
|
||||
) -> TypeBound {
|
||||
match bound {
|
||||
TypeBound::Path(path, modifier) => {
|
||||
TypeBound::Path(copy_path(path, from, from_source_map, to, to_source_map), *modifier)
|
||||
}
|
||||
TypeBound::ForLifetime(lifetimes, path) => TypeBound::ForLifetime(
|
||||
lifetimes.clone(),
|
||||
copy_path(path, from, from_source_map, to, to_source_map),
|
||||
),
|
||||
TypeBound::Lifetime(lifetime) => TypeBound::Lifetime(lifetime.clone()),
|
||||
TypeBound::Use(use_args) => TypeBound::Use(use_args.clone()),
|
||||
TypeBound::Error => TypeBound::Error,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,16 +17,17 @@ pub mod type_ref;
|
|||
|
||||
use std::fmt;
|
||||
|
||||
use hir_expand::name::Name;
|
||||
use intern::{Interned, Symbol};
|
||||
use hir_expand::{name::Name, MacroDefId};
|
||||
use intern::Symbol;
|
||||
use la_arena::{Idx, RawIdx};
|
||||
use rustc_apfloat::ieee::{Half as f16, Quad as f128};
|
||||
use syntax::ast;
|
||||
use type_ref::TypeRefId;
|
||||
|
||||
use crate::{
|
||||
builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
|
||||
path::{GenericArgs, Path},
|
||||
type_ref::{Mutability, Rawness, TypeRef},
|
||||
type_ref::{Mutability, Rawness},
|
||||
BlockId, ConstBlockId,
|
||||
};
|
||||
|
||||
|
|
@ -48,6 +49,22 @@ pub enum ExprOrPatId {
|
|||
ExprId(ExprId),
|
||||
PatId(PatId),
|
||||
}
|
||||
|
||||
impl ExprOrPatId {
|
||||
pub fn as_expr(self) -> Option<ExprId> {
|
||||
match self {
|
||||
Self::ExprId(v) => Some(v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_pat(self) -> Option<PatId> {
|
||||
match self {
|
||||
Self::PatId(v) => Some(v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
stdx::impl_from!(ExprId, PatId for ExprOrPatId);
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
|
|
@ -204,7 +221,6 @@ pub enum Expr {
|
|||
Call {
|
||||
callee: ExprId,
|
||||
args: Box<[ExprId]>,
|
||||
is_assignee_expr: bool,
|
||||
},
|
||||
MethodCall {
|
||||
receiver: ExprId,
|
||||
|
|
@ -239,8 +255,6 @@ pub enum Expr {
|
|||
path: Option<Box<Path>>,
|
||||
fields: Box<[RecordLitField]>,
|
||||
spread: Option<ExprId>,
|
||||
ellipsis: bool,
|
||||
is_assignee_expr: bool,
|
||||
},
|
||||
Field {
|
||||
expr: ExprId,
|
||||
|
|
@ -251,7 +265,7 @@ pub enum Expr {
|
|||
},
|
||||
Cast {
|
||||
expr: ExprId,
|
||||
type_ref: Interned<TypeRef>,
|
||||
type_ref: TypeRefId,
|
||||
},
|
||||
Ref {
|
||||
expr: ExprId,
|
||||
|
|
@ -265,11 +279,17 @@ pub enum Expr {
|
|||
expr: ExprId,
|
||||
op: UnaryOp,
|
||||
},
|
||||
/// `op` cannot be bare `=` (but can be `op=`), these are lowered to `Assignment` instead.
|
||||
BinaryOp {
|
||||
lhs: ExprId,
|
||||
rhs: ExprId,
|
||||
op: Option<BinaryOp>,
|
||||
},
|
||||
// Assignments need a special treatment because of destructuring assignment.
|
||||
Assignment {
|
||||
target: PatId,
|
||||
value: ExprId,
|
||||
},
|
||||
Range {
|
||||
lhs: Option<ExprId>,
|
||||
rhs: Option<ExprId>,
|
||||
|
|
@ -278,19 +298,17 @@ pub enum Expr {
|
|||
Index {
|
||||
base: ExprId,
|
||||
index: ExprId,
|
||||
is_assignee_expr: bool,
|
||||
},
|
||||
Closure {
|
||||
args: Box<[PatId]>,
|
||||
arg_types: Box<[Option<Interned<TypeRef>>]>,
|
||||
ret_type: Option<Interned<TypeRef>>,
|
||||
arg_types: Box<[Option<TypeRefId>]>,
|
||||
ret_type: Option<TypeRefId>,
|
||||
body: ExprId,
|
||||
closure_kind: ClosureKind,
|
||||
capture_by: CaptureBy,
|
||||
},
|
||||
Tuple {
|
||||
exprs: Box<[ExprId]>,
|
||||
is_assignee_expr: bool,
|
||||
},
|
||||
Array(Array),
|
||||
Literal(Literal),
|
||||
|
|
@ -301,7 +319,7 @@ pub enum Expr {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct OffsetOf {
|
||||
pub container: Interned<TypeRef>,
|
||||
pub container: TypeRefId,
|
||||
pub fields: Box<[Name]>,
|
||||
}
|
||||
|
||||
|
|
@ -446,7 +464,7 @@ pub enum Movability {
|
|||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub enum Array {
|
||||
ElementList { elements: Box<[ExprId]>, is_assignee_expr: bool },
|
||||
ElementList { elements: Box<[ExprId]> },
|
||||
Repeat { initializer: ExprId, repeat: ExprId },
|
||||
}
|
||||
|
||||
|
|
@ -467,7 +485,7 @@ pub struct RecordLitField {
|
|||
pub enum Statement {
|
||||
Let {
|
||||
pat: PatId,
|
||||
type_ref: Option<Interned<TypeRef>>,
|
||||
type_ref: Option<TypeRefId>,
|
||||
initializer: Option<ExprId>,
|
||||
else_branch: Option<ExprId>,
|
||||
},
|
||||
|
|
@ -475,133 +493,13 @@ pub enum Statement {
|
|||
expr: ExprId,
|
||||
has_semi: bool,
|
||||
},
|
||||
// At the moment, we only use this to figure out if a return expression
|
||||
// is really the last statement of a block. See #16566
|
||||
Item,
|
||||
Item(Item),
|
||||
}
|
||||
|
||||
impl Expr {
|
||||
pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
|
||||
match self {
|
||||
Expr::Missing => {}
|
||||
Expr::Path(_) | Expr::OffsetOf(_) => {}
|
||||
Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op {
|
||||
AsmOperand::In { expr, .. }
|
||||
| AsmOperand::Out { expr: Some(expr), .. }
|
||||
| AsmOperand::InOut { expr, .. } => f(*expr),
|
||||
AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
|
||||
f(*in_expr);
|
||||
if let Some(out_expr) = out_expr {
|
||||
f(*out_expr);
|
||||
}
|
||||
}
|
||||
AsmOperand::Out { expr: None, .. }
|
||||
| AsmOperand::Const(_)
|
||||
| AsmOperand::Label(_)
|
||||
| AsmOperand::Sym(_) => (),
|
||||
}),
|
||||
Expr::If { condition, then_branch, else_branch } => {
|
||||
f(*condition);
|
||||
f(*then_branch);
|
||||
if let &Some(else_branch) = else_branch {
|
||||
f(else_branch);
|
||||
}
|
||||
}
|
||||
Expr::Let { expr, .. } => {
|
||||
f(*expr);
|
||||
}
|
||||
Expr::Const(_) => (),
|
||||
Expr::Block { statements, tail, .. }
|
||||
| Expr::Unsafe { statements, tail, .. }
|
||||
| Expr::Async { statements, tail, .. } => {
|
||||
for stmt in statements.iter() {
|
||||
match stmt {
|
||||
Statement::Let { initializer, else_branch, .. } => {
|
||||
if let &Some(expr) = initializer {
|
||||
f(expr);
|
||||
}
|
||||
if let &Some(expr) = else_branch {
|
||||
f(expr);
|
||||
}
|
||||
}
|
||||
Statement::Expr { expr: expression, .. } => f(*expression),
|
||||
Statement::Item => (),
|
||||
}
|
||||
}
|
||||
if let &Some(expr) = tail {
|
||||
f(expr);
|
||||
}
|
||||
}
|
||||
Expr::Loop { body, .. } => f(*body),
|
||||
Expr::Call { callee, args, .. } => {
|
||||
f(*callee);
|
||||
args.iter().copied().for_each(f);
|
||||
}
|
||||
Expr::MethodCall { receiver, args, .. } => {
|
||||
f(*receiver);
|
||||
args.iter().copied().for_each(f);
|
||||
}
|
||||
Expr::Match { expr, arms } => {
|
||||
f(*expr);
|
||||
arms.iter().map(|arm| arm.expr).for_each(f);
|
||||
}
|
||||
Expr::Continue { .. } => {}
|
||||
Expr::Break { expr, .. }
|
||||
| Expr::Return { expr }
|
||||
| Expr::Yield { expr }
|
||||
| Expr::Yeet { expr } => {
|
||||
if let &Some(expr) = expr {
|
||||
f(expr);
|
||||
}
|
||||
}
|
||||
Expr::Become { expr } => f(*expr),
|
||||
Expr::RecordLit { fields, spread, .. } => {
|
||||
for field in fields.iter() {
|
||||
f(field.expr);
|
||||
}
|
||||
if let &Some(expr) = spread {
|
||||
f(expr);
|
||||
}
|
||||
}
|
||||
Expr::Closure { body, .. } => {
|
||||
f(*body);
|
||||
}
|
||||
Expr::BinaryOp { lhs, rhs, .. } => {
|
||||
f(*lhs);
|
||||
f(*rhs);
|
||||
}
|
||||
Expr::Range { lhs, rhs, .. } => {
|
||||
if let &Some(lhs) = rhs {
|
||||
f(lhs);
|
||||
}
|
||||
if let &Some(rhs) = lhs {
|
||||
f(rhs);
|
||||
}
|
||||
}
|
||||
Expr::Index { base, index, .. } => {
|
||||
f(*base);
|
||||
f(*index);
|
||||
}
|
||||
Expr::Field { expr, .. }
|
||||
| Expr::Await { expr }
|
||||
| Expr::Cast { expr, .. }
|
||||
| Expr::Ref { expr, .. }
|
||||
| Expr::UnaryOp { expr, .. }
|
||||
| Expr::Box { expr } => {
|
||||
f(*expr);
|
||||
}
|
||||
Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f),
|
||||
Expr::Array(a) => match a {
|
||||
Array::ElementList { elements, .. } => elements.iter().copied().for_each(f),
|
||||
Array::Repeat { initializer, repeat } => {
|
||||
f(*initializer);
|
||||
f(*repeat)
|
||||
}
|
||||
},
|
||||
Expr::Literal(_) => {}
|
||||
Expr::Underscore => {}
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Item {
|
||||
MacroDef(Box<MacroDefId>),
|
||||
Other,
|
||||
}
|
||||
|
||||
/// Explicit binding annotations given in the HIR for a binding. Note
|
||||
|
|
@ -665,18 +563,49 @@ pub struct RecordFieldPat {
|
|||
pub enum Pat {
|
||||
Missing,
|
||||
Wild,
|
||||
Tuple { args: Box<[PatId]>, ellipsis: Option<u32> },
|
||||
Tuple {
|
||||
args: Box<[PatId]>,
|
||||
ellipsis: Option<u32>,
|
||||
},
|
||||
Or(Box<[PatId]>),
|
||||
Record { path: Option<Box<Path>>, args: Box<[RecordFieldPat]>, ellipsis: bool },
|
||||
Range { start: Option<Box<LiteralOrConst>>, end: Option<Box<LiteralOrConst>> },
|
||||
Slice { prefix: Box<[PatId]>, slice: Option<PatId>, suffix: Box<[PatId]> },
|
||||
Path(Box<Path>),
|
||||
Record {
|
||||
path: Option<Box<Path>>,
|
||||
args: Box<[RecordFieldPat]>,
|
||||
ellipsis: bool,
|
||||
},
|
||||
Range {
|
||||
start: Option<Box<LiteralOrConst>>,
|
||||
end: Option<Box<LiteralOrConst>>,
|
||||
},
|
||||
Slice {
|
||||
prefix: Box<[PatId]>,
|
||||
slice: Option<PatId>,
|
||||
suffix: Box<[PatId]>,
|
||||
},
|
||||
/// This might refer to a variable if a single segment path (specifically, on destructuring assignment).
|
||||
Path(Path),
|
||||
Lit(ExprId),
|
||||
Bind { id: BindingId, subpat: Option<PatId> },
|
||||
TupleStruct { path: Option<Box<Path>>, args: Box<[PatId]>, ellipsis: Option<u32> },
|
||||
Ref { pat: PatId, mutability: Mutability },
|
||||
Box { inner: PatId },
|
||||
Bind {
|
||||
id: BindingId,
|
||||
subpat: Option<PatId>,
|
||||
},
|
||||
TupleStruct {
|
||||
path: Option<Box<Path>>,
|
||||
args: Box<[PatId]>,
|
||||
ellipsis: Option<u32>,
|
||||
},
|
||||
Ref {
|
||||
pat: PatId,
|
||||
mutability: Mutability,
|
||||
},
|
||||
Box {
|
||||
inner: PatId,
|
||||
},
|
||||
ConstBlock(ExprId),
|
||||
/// An expression inside a pattern. That can only occur inside assignments.
|
||||
///
|
||||
/// E.g. in `(a, *b) = (1, &mut 2)`, `*b` is an expression.
|
||||
Expr(ExprId),
|
||||
}
|
||||
|
||||
impl Pat {
|
||||
|
|
@ -687,7 +616,8 @@ impl Pat {
|
|||
| Pat::Path(..)
|
||||
| Pat::ConstBlock(..)
|
||||
| Pat::Wild
|
||||
| Pat::Missing => {}
|
||||
| Pat::Missing
|
||||
| Pat::Expr(_) => {}
|
||||
Pat::Bind { subpat, .. } => {
|
||||
subpat.iter().copied().for_each(f);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,22 +2,27 @@
|
|||
//! be directly created from an ast::TypeRef, without further queries.
|
||||
|
||||
use core::fmt;
|
||||
use std::fmt::Write;
|
||||
use std::{fmt::Write, ops::Index};
|
||||
|
||||
use hir_expand::{
|
||||
db::ExpandDatabase,
|
||||
name::{AsName, Name},
|
||||
AstId,
|
||||
AstId, InFile,
|
||||
};
|
||||
use intern::{sym, Interned, Symbol};
|
||||
use intern::{sym, Symbol};
|
||||
use la_arena::{Arena, ArenaMap, Idx};
|
||||
use span::Edition;
|
||||
use syntax::ast::{self, HasGenericArgs, HasName, IsString};
|
||||
use stdx::thin_vec::{thin_vec_with_header_struct, EmptyOptimizedThinVec, ThinVec};
|
||||
use syntax::{
|
||||
ast::{self, HasGenericArgs, HasName, IsString},
|
||||
AstPtr,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
|
||||
hir::Literal,
|
||||
lower::LowerCtx,
|
||||
path::Path,
|
||||
path::{GenericArg, Path},
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
|
|
@ -104,35 +109,90 @@ impl TraitRef {
|
|||
}
|
||||
}
|
||||
|
||||
thin_vec_with_header_struct! {
|
||||
pub new(pub(crate)) struct FnType, FnTypeHeader {
|
||||
pub params: [(Option<Name>, TypeRefId)],
|
||||
pub is_varargs: bool,
|
||||
pub is_unsafe: bool,
|
||||
pub abi: Option<Symbol>; ref,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct ArrayType {
|
||||
pub ty: TypeRefId,
|
||||
// FIXME: This should be Ast<ConstArg>
|
||||
pub len: ConstRef,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct RefType {
|
||||
pub ty: TypeRefId,
|
||||
pub lifetime: Option<LifetimeRef>,
|
||||
pub mutability: Mutability,
|
||||
}
|
||||
|
||||
/// Compare ty::Ty
|
||||
///
|
||||
/// Note: Most users of `TypeRef` that end up in the salsa database intern it using
|
||||
/// `Interned<TypeRef>` to save space. But notably, nested `TypeRef`s are not interned, since that
|
||||
/// does not seem to save any noticeable amount of memory.
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum TypeRef {
|
||||
Never,
|
||||
Placeholder,
|
||||
Tuple(Vec<TypeRef>),
|
||||
Tuple(EmptyOptimizedThinVec<TypeRefId>),
|
||||
Path(Path),
|
||||
RawPtr(Box<TypeRef>, Mutability),
|
||||
Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
|
||||
// FIXME: This should be Array(Box<TypeRef>, Ast<ConstArg>),
|
||||
Array(Box<TypeRef>, ConstRef),
|
||||
Slice(Box<TypeRef>),
|
||||
RawPtr(TypeRefId, Mutability),
|
||||
Reference(Box<RefType>),
|
||||
Array(Box<ArrayType>),
|
||||
Slice(TypeRefId),
|
||||
/// A fn pointer. Last element of the vector is the return type.
|
||||
Fn(
|
||||
Box<[(Option<Name>, TypeRef)]>,
|
||||
bool, /*varargs*/
|
||||
bool, /*is_unsafe*/
|
||||
Option<Symbol>, /* abi */
|
||||
),
|
||||
ImplTrait(Vec<Interned<TypeBound>>),
|
||||
DynTrait(Vec<Interned<TypeBound>>),
|
||||
Fn(FnType),
|
||||
ImplTrait(ThinVec<TypeBound>),
|
||||
DynTrait(ThinVec<TypeBound>),
|
||||
Macro(AstId<ast::MacroCall>),
|
||||
Error,
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
const _: () = assert!(size_of::<TypeRef>() == 16);
|
||||
|
||||
pub type TypeRefId = Idx<TypeRef>;
|
||||
|
||||
#[derive(Default, Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct TypesMap {
|
||||
pub(crate) types: Arena<TypeRef>,
|
||||
}
|
||||
|
||||
impl TypesMap {
|
||||
pub const EMPTY: &TypesMap = &TypesMap { types: Arena::new() };
|
||||
|
||||
pub(crate) fn shrink_to_fit(&mut self) {
|
||||
let TypesMap { types } = self;
|
||||
types.shrink_to_fit();
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<TypeRefId> for TypesMap {
|
||||
type Output = TypeRef;
|
||||
|
||||
fn index(&self, index: TypeRefId) -> &Self::Output {
|
||||
&self.types[index]
|
||||
}
|
||||
}
|
||||
|
||||
pub type TypePtr = AstPtr<ast::Type>;
|
||||
pub type TypeSource = InFile<TypePtr>;
|
||||
|
||||
#[derive(Default, Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct TypesSourceMap {
|
||||
pub(crate) types_map_back: ArenaMap<TypeRefId, TypeSource>,
|
||||
}
|
||||
|
||||
impl TypesSourceMap {
|
||||
pub(crate) fn shrink_to_fit(&mut self) {
|
||||
let TypesSourceMap { types_map_back } = self;
|
||||
types_map_back.shrink_to_fit();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct LifetimeRef {
|
||||
pub name: Name,
|
||||
|
|
@ -157,12 +217,22 @@ pub enum TypeBound {
|
|||
Path(Path, TraitBoundModifier),
|
||||
ForLifetime(Box<[Name]>, Path),
|
||||
Lifetime(LifetimeRef),
|
||||
Use(Box<[UseArgRef]>),
|
||||
Error,
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
const _: [(); 32] = [(); ::std::mem::size_of::<TypeBound>()];
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum UseArgRef {
|
||||
Name(Name),
|
||||
Lifetime(LifetimeRef),
|
||||
}
|
||||
|
||||
/// A modifier on a bound, currently this is only used for `?Sized`, where the
|
||||
/// modifier is `Maybe`.
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum TraitBoundModifier {
|
||||
None,
|
||||
Maybe,
|
||||
|
|
@ -170,12 +240,12 @@ pub enum TraitBoundModifier {
|
|||
|
||||
impl TypeRef {
|
||||
/// Converts an `ast::TypeRef` to a `hir::TypeRef`.
|
||||
pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> Self {
|
||||
match node {
|
||||
ast::Type::ParenType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()),
|
||||
ast::Type::TupleType(inner) => {
|
||||
TypeRef::Tuple(inner.fields().map(|it| TypeRef::from_ast(ctx, it)).collect())
|
||||
}
|
||||
pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> TypeRefId {
|
||||
let ty = match &node {
|
||||
ast::Type::ParenType(inner) => return TypeRef::from_ast_opt(ctx, inner.ty()),
|
||||
ast::Type::TupleType(inner) => TypeRef::Tuple(EmptyOptimizedThinVec::from_iter(
|
||||
Vec::from_iter(inner.fields().map(|it| TypeRef::from_ast(ctx, it))),
|
||||
)),
|
||||
ast::Type::NeverType(..) => TypeRef::Never,
|
||||
ast::Type::PathType(inner) => {
|
||||
// FIXME: Use `Path::from_src`
|
||||
|
|
@ -188,20 +258,21 @@ impl TypeRef {
|
|||
ast::Type::PtrType(inner) => {
|
||||
let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty());
|
||||
let mutability = Mutability::from_mutable(inner.mut_token().is_some());
|
||||
TypeRef::RawPtr(Box::new(inner_ty), mutability)
|
||||
TypeRef::RawPtr(inner_ty, mutability)
|
||||
}
|
||||
ast::Type::ArrayType(inner) => {
|
||||
let len = ConstRef::from_const_arg(ctx, inner.const_arg());
|
||||
TypeRef::Array(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())), len)
|
||||
}
|
||||
ast::Type::SliceType(inner) => {
|
||||
TypeRef::Slice(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())))
|
||||
TypeRef::Array(Box::new(ArrayType {
|
||||
ty: TypeRef::from_ast_opt(ctx, inner.ty()),
|
||||
len,
|
||||
}))
|
||||
}
|
||||
ast::Type::SliceType(inner) => TypeRef::Slice(TypeRef::from_ast_opt(ctx, inner.ty())),
|
||||
ast::Type::RefType(inner) => {
|
||||
let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty());
|
||||
let lifetime = inner.lifetime().map(|lt| LifetimeRef::new(<));
|
||||
let mutability = Mutability::from_mutable(inner.mut_token().is_some());
|
||||
TypeRef::Reference(Box::new(inner_ty), lifetime, mutability)
|
||||
TypeRef::Reference(Box::new(RefType { ty: inner_ty, lifetime, mutability }))
|
||||
}
|
||||
ast::Type::InferType(_inner) => TypeRef::Placeholder,
|
||||
ast::Type::FnPtrType(inner) => {
|
||||
|
|
@ -209,7 +280,7 @@ impl TypeRef {
|
|||
.ret_type()
|
||||
.and_then(|rt| rt.ty())
|
||||
.map(|it| TypeRef::from_ast(ctx, it))
|
||||
.unwrap_or_else(|| TypeRef::Tuple(Vec::new()));
|
||||
.unwrap_or_else(|| ctx.alloc_type_ref_desugared(TypeRef::unit()));
|
||||
let mut is_varargs = false;
|
||||
let mut params = if let Some(pl) = inner.param_list() {
|
||||
if let Some(param) = pl.params().last() {
|
||||
|
|
@ -241,10 +312,10 @@ impl TypeRef {
|
|||
|
||||
let abi = inner.abi().map(lower_abi);
|
||||
params.push((None, ret_ty));
|
||||
TypeRef::Fn(params.into(), is_varargs, inner.unsafe_token().is_some(), abi)
|
||||
TypeRef::Fn(FnType::new(is_varargs, inner.unsafe_token().is_some(), abi, params))
|
||||
}
|
||||
// for types are close enough for our purposes to the inner type for now...
|
||||
ast::Type::ForType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()),
|
||||
ast::Type::ForType(inner) => return TypeRef::from_ast_opt(ctx, inner.ty()),
|
||||
ast::Type::ImplTraitType(inner) => {
|
||||
if ctx.outer_impl_trait() {
|
||||
// Disallow nested impl traits
|
||||
|
|
@ -261,74 +332,74 @@ impl TypeRef {
|
|||
Some(mc) => TypeRef::Macro(ctx.ast_id(&mc)),
|
||||
None => TypeRef::Error,
|
||||
},
|
||||
}
|
||||
};
|
||||
ctx.alloc_type_ref(ty, AstPtr::new(&node))
|
||||
}
|
||||
|
||||
pub(crate) fn from_ast_opt(ctx: &LowerCtx<'_>, node: Option<ast::Type>) -> Self {
|
||||
pub(crate) fn from_ast_opt(ctx: &LowerCtx<'_>, node: Option<ast::Type>) -> TypeRefId {
|
||||
match node {
|
||||
Some(node) => TypeRef::from_ast(ctx, node),
|
||||
None => TypeRef::Error,
|
||||
None => ctx.alloc_error_type(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn unit() -> TypeRef {
|
||||
TypeRef::Tuple(Vec::new())
|
||||
TypeRef::Tuple(EmptyOptimizedThinVec::empty())
|
||||
}
|
||||
|
||||
pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) {
|
||||
go(self, f);
|
||||
pub fn walk(this: TypeRefId, map: &TypesMap, f: &mut impl FnMut(&TypeRef)) {
|
||||
go(this, f, map);
|
||||
|
||||
fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
|
||||
fn go(type_ref: TypeRefId, f: &mut impl FnMut(&TypeRef), map: &TypesMap) {
|
||||
let type_ref = &map[type_ref];
|
||||
f(type_ref);
|
||||
match type_ref {
|
||||
TypeRef::Fn(params, _, _, _) => {
|
||||
params.iter().for_each(|(_, param_type)| go(param_type, f))
|
||||
TypeRef::Fn(fn_) => {
|
||||
fn_.params().iter().for_each(|&(_, param_type)| go(param_type, f, map))
|
||||
}
|
||||
TypeRef::Tuple(types) => types.iter().for_each(|t| go(t, f)),
|
||||
TypeRef::RawPtr(type_ref, _)
|
||||
| TypeRef::Reference(type_ref, ..)
|
||||
| TypeRef::Array(type_ref, _)
|
||||
| TypeRef::Slice(type_ref) => go(type_ref, f),
|
||||
TypeRef::Tuple(types) => types.iter().for_each(|&t| go(t, f, map)),
|
||||
TypeRef::RawPtr(type_ref, _) | TypeRef::Slice(type_ref) => go(*type_ref, f, map),
|
||||
TypeRef::Reference(it) => go(it.ty, f, map),
|
||||
TypeRef::Array(it) => go(it.ty, f, map),
|
||||
TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
|
||||
for bound in bounds {
|
||||
match bound.as_ref() {
|
||||
match bound {
|
||||
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
|
||||
go_path(path, f)
|
||||
go_path(path, f, map)
|
||||
}
|
||||
TypeBound::Lifetime(_) | TypeBound::Error => (),
|
||||
TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
TypeRef::Path(path) => go_path(path, f),
|
||||
TypeRef::Path(path) => go_path(path, f, map),
|
||||
TypeRef::Never | TypeRef::Placeholder | TypeRef::Macro(_) | TypeRef::Error => {}
|
||||
};
|
||||
}
|
||||
|
||||
fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef)) {
|
||||
fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef), map: &TypesMap) {
|
||||
if let Some(type_ref) = path.type_anchor() {
|
||||
go(type_ref, f);
|
||||
go(type_ref, f, map);
|
||||
}
|
||||
for segment in path.segments().iter() {
|
||||
if let Some(args_and_bindings) = segment.args_and_bindings {
|
||||
for arg in args_and_bindings.args.iter() {
|
||||
match arg {
|
||||
crate::path::GenericArg::Type(type_ref) => {
|
||||
go(type_ref, f);
|
||||
GenericArg::Type(type_ref) => {
|
||||
go(*type_ref, f, map);
|
||||
}
|
||||
crate::path::GenericArg::Const(_)
|
||||
| crate::path::GenericArg::Lifetime(_) => {}
|
||||
GenericArg::Const(_) | GenericArg::Lifetime(_) => {}
|
||||
}
|
||||
}
|
||||
for binding in args_and_bindings.bindings.iter() {
|
||||
if let Some(type_ref) = &binding.type_ref {
|
||||
go(type_ref, f);
|
||||
if let Some(type_ref) = binding.type_ref {
|
||||
go(type_ref, f, map);
|
||||
}
|
||||
for bound in binding.bounds.iter() {
|
||||
match bound.as_ref() {
|
||||
match bound {
|
||||
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
|
||||
go_path(path, f)
|
||||
go_path(path, f, map)
|
||||
}
|
||||
TypeBound::Lifetime(_) | TypeBound::Error => (),
|
||||
TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -341,11 +412,13 @@ impl TypeRef {
|
|||
pub(crate) fn type_bounds_from_ast(
|
||||
lower_ctx: &LowerCtx<'_>,
|
||||
type_bounds_opt: Option<ast::TypeBoundList>,
|
||||
) -> Vec<Interned<TypeBound>> {
|
||||
) -> ThinVec<TypeBound> {
|
||||
if let Some(type_bounds) = type_bounds_opt {
|
||||
type_bounds.bounds().map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it))).collect()
|
||||
ThinVec::from_iter(Vec::from_iter(
|
||||
type_bounds.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)),
|
||||
))
|
||||
} else {
|
||||
vec![]
|
||||
ThinVec::from_iter([])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -380,7 +453,16 @@ impl TypeBound {
|
|||
None => TypeBound::Error,
|
||||
}
|
||||
}
|
||||
ast::TypeBoundKind::Use(_) => TypeBound::Error,
|
||||
ast::TypeBoundKind::Use(gal) => TypeBound::Use(
|
||||
gal.use_bound_generic_args()
|
||||
.map(|p| match p {
|
||||
ast::UseBoundGenericArg::Lifetime(l) => {
|
||||
UseArgRef::Lifetime(LifetimeRef::new(&l))
|
||||
}
|
||||
ast::UseBoundGenericArg::NameRef(n) => UseArgRef::Name(n.as_name()),
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
ast::TypeBoundKind::Lifetime(lifetime) => {
|
||||
TypeBound::Lifetime(LifetimeRef::new(&lifetime))
|
||||
}
|
||||
|
|
@ -391,7 +473,7 @@ impl TypeBound {
|
|||
match self {
|
||||
TypeBound::Path(p, m) => Some((p, m)),
|
||||
TypeBound::ForLifetime(_, p) => Some((p, &TraitBoundModifier::None)),
|
||||
TypeBound::Lifetime(_) | TypeBound::Error => None,
|
||||
TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ use crate::{
|
|||
db::DefDatabase,
|
||||
generics::GenericParams,
|
||||
path::{GenericArgs, ImportAlias, ModPath, Path, PathKind},
|
||||
type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
|
||||
type_ref::{Mutability, TraitRef, TypeBound, TypeRefId, TypesMap, TypesSourceMap},
|
||||
visibility::{RawVisibility, VisibilityExplicitness},
|
||||
BlockId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup,
|
||||
};
|
||||
|
|
@ -100,14 +100,20 @@ pub struct ItemTree {
|
|||
|
||||
impl ItemTree {
|
||||
pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
|
||||
let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
|
||||
static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
|
||||
db.file_item_tree_with_source_map(file_id).0
|
||||
}
|
||||
|
||||
let syntax = db.parse_or_expand(file_id);
|
||||
pub(crate) fn file_item_tree_with_source_map_query(
|
||||
db: &dyn DefDatabase,
|
||||
file_id: HirFileId,
|
||||
) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
|
||||
let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
|
||||
static EMPTY: OnceLock<(Arc<ItemTree>, Arc<ItemTreeSourceMaps>)> = OnceLock::new();
|
||||
|
||||
let ctx = lower::Ctx::new(db, file_id);
|
||||
let syntax = db.parse_or_expand(file_id);
|
||||
let mut top_attrs = None;
|
||||
let mut item_tree = match_ast! {
|
||||
let (mut item_tree, source_maps) = match_ast! {
|
||||
match syntax {
|
||||
ast::SourceFile(file) => {
|
||||
top_attrs = Some(RawAttrs::new(db.upcast(), &file, ctx.span_map()));
|
||||
|
|
@ -137,42 +143,55 @@ impl ItemTree {
|
|||
{
|
||||
EMPTY
|
||||
.get_or_init(|| {
|
||||
Arc::new(ItemTree {
|
||||
top_level: SmallVec::new_const(),
|
||||
attrs: FxHashMap::default(),
|
||||
data: None,
|
||||
})
|
||||
(
|
||||
Arc::new(ItemTree {
|
||||
top_level: SmallVec::new_const(),
|
||||
attrs: FxHashMap::default(),
|
||||
data: None,
|
||||
}),
|
||||
Arc::default(),
|
||||
)
|
||||
})
|
||||
.clone()
|
||||
} else {
|
||||
item_tree.shrink_to_fit();
|
||||
Arc::new(item_tree)
|
||||
(Arc::new(item_tree), Arc::new(source_maps))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> {
|
||||
db.block_item_tree_with_source_map(block).0
|
||||
}
|
||||
|
||||
pub(crate) fn block_item_tree_with_source_map_query(
|
||||
db: &dyn DefDatabase,
|
||||
block: BlockId,
|
||||
) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
|
||||
let _p = tracing::info_span!("block_item_tree_query", ?block).entered();
|
||||
static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
|
||||
static EMPTY: OnceLock<(Arc<ItemTree>, Arc<ItemTreeSourceMaps>)> = OnceLock::new();
|
||||
|
||||
let loc = block.lookup(db);
|
||||
let block = loc.ast_id.to_node(db.upcast());
|
||||
|
||||
let ctx = lower::Ctx::new(db, loc.ast_id.file_id);
|
||||
let mut item_tree = ctx.lower_block(&block);
|
||||
let (mut item_tree, source_maps) = ctx.lower_block(&block);
|
||||
if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty()
|
||||
{
|
||||
EMPTY
|
||||
.get_or_init(|| {
|
||||
Arc::new(ItemTree {
|
||||
top_level: SmallVec::new_const(),
|
||||
attrs: FxHashMap::default(),
|
||||
data: None,
|
||||
})
|
||||
(
|
||||
Arc::new(ItemTree {
|
||||
top_level: SmallVec::new_const(),
|
||||
attrs: FxHashMap::default(),
|
||||
data: None,
|
||||
}),
|
||||
Arc::default(),
|
||||
)
|
||||
})
|
||||
.clone()
|
||||
} else {
|
||||
item_tree.shrink_to_fit();
|
||||
Arc::new(item_tree)
|
||||
(Arc::new(item_tree), Arc::new(source_maps))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -309,6 +328,160 @@ struct ItemTreeData {
|
|||
vis: ItemVisibilities,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Eq, PartialEq)]
|
||||
pub struct ItemTreeSourceMaps {
|
||||
all_concatenated: Box<[TypesSourceMap]>,
|
||||
structs_offset: u32,
|
||||
unions_offset: u32,
|
||||
enum_generics_offset: u32,
|
||||
variants_offset: u32,
|
||||
consts_offset: u32,
|
||||
statics_offset: u32,
|
||||
trait_generics_offset: u32,
|
||||
trait_alias_generics_offset: u32,
|
||||
impls_offset: u32,
|
||||
type_aliases_offset: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct GenericItemSourceMap<'a>(&'a [TypesSourceMap; 2]);
|
||||
|
||||
impl<'a> GenericItemSourceMap<'a> {
|
||||
#[inline]
|
||||
pub fn item(self) -> &'a TypesSourceMap {
|
||||
&self.0[0]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn generics(self) -> &'a TypesSourceMap {
|
||||
&self.0[1]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Eq, PartialEq)]
|
||||
pub struct GenericItemSourceMapBuilder {
|
||||
pub item: TypesSourceMap,
|
||||
pub generics: TypesSourceMap,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Eq, PartialEq)]
|
||||
struct ItemTreeSourceMapsBuilder {
|
||||
functions: Vec<GenericItemSourceMapBuilder>,
|
||||
structs: Vec<GenericItemSourceMapBuilder>,
|
||||
unions: Vec<GenericItemSourceMapBuilder>,
|
||||
enum_generics: Vec<TypesSourceMap>,
|
||||
variants: Vec<TypesSourceMap>,
|
||||
consts: Vec<TypesSourceMap>,
|
||||
statics: Vec<TypesSourceMap>,
|
||||
trait_generics: Vec<TypesSourceMap>,
|
||||
trait_alias_generics: Vec<TypesSourceMap>,
|
||||
impls: Vec<GenericItemSourceMapBuilder>,
|
||||
type_aliases: Vec<GenericItemSourceMapBuilder>,
|
||||
}
|
||||
|
||||
impl ItemTreeSourceMapsBuilder {
|
||||
fn build(self) -> ItemTreeSourceMaps {
|
||||
let ItemTreeSourceMapsBuilder {
|
||||
functions,
|
||||
structs,
|
||||
unions,
|
||||
enum_generics,
|
||||
variants,
|
||||
consts,
|
||||
statics,
|
||||
trait_generics,
|
||||
trait_alias_generics,
|
||||
impls,
|
||||
type_aliases,
|
||||
} = self;
|
||||
let structs_offset = functions.len() as u32 * 2;
|
||||
let unions_offset = structs_offset + (structs.len() as u32 * 2);
|
||||
let enum_generics_offset = unions_offset + (unions.len() as u32 * 2);
|
||||
let variants_offset = enum_generics_offset + (enum_generics.len() as u32);
|
||||
let consts_offset = variants_offset + (variants.len() as u32);
|
||||
let statics_offset = consts_offset + (consts.len() as u32);
|
||||
let trait_generics_offset = statics_offset + (statics.len() as u32);
|
||||
let trait_alias_generics_offset = trait_generics_offset + (trait_generics.len() as u32);
|
||||
let impls_offset = trait_alias_generics_offset + (trait_alias_generics.len() as u32);
|
||||
let type_aliases_offset = impls_offset + (impls.len() as u32 * 2);
|
||||
let all_concatenated = generics_concat(functions)
|
||||
.chain(generics_concat(structs))
|
||||
.chain(generics_concat(unions))
|
||||
.chain(enum_generics)
|
||||
.chain(variants)
|
||||
.chain(consts)
|
||||
.chain(statics)
|
||||
.chain(trait_generics)
|
||||
.chain(trait_alias_generics)
|
||||
.chain(generics_concat(impls))
|
||||
.chain(generics_concat(type_aliases))
|
||||
.collect();
|
||||
return ItemTreeSourceMaps {
|
||||
all_concatenated,
|
||||
structs_offset,
|
||||
unions_offset,
|
||||
enum_generics_offset,
|
||||
variants_offset,
|
||||
consts_offset,
|
||||
statics_offset,
|
||||
trait_generics_offset,
|
||||
trait_alias_generics_offset,
|
||||
impls_offset,
|
||||
type_aliases_offset,
|
||||
};
|
||||
|
||||
fn generics_concat(
|
||||
source_maps: Vec<GenericItemSourceMapBuilder>,
|
||||
) -> impl Iterator<Item = TypesSourceMap> {
|
||||
source_maps.into_iter().flat_map(|it| [it.item, it.generics])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ItemTreeSourceMaps {
|
||||
#[inline]
|
||||
fn generic_item(&self, offset: u32, index: u32) -> GenericItemSourceMap<'_> {
|
||||
GenericItemSourceMap(
|
||||
self.all_concatenated[(offset + (index * 2)) as usize..][..2].try_into().unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn non_generic_item(&self, offset: u32, index: u32) -> &TypesSourceMap {
|
||||
&self.all_concatenated[(offset + index) as usize]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn function(&self, index: FileItemTreeId<Function>) -> GenericItemSourceMap<'_> {
|
||||
self.generic_item(0, index.0.into_raw().into_u32())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! index_item_source_maps {
|
||||
( $( $name:ident; $field:ident[$tree_id:ident]; $fn:ident; $ret:ty, )* ) => {
|
||||
impl ItemTreeSourceMaps {
|
||||
$(
|
||||
#[inline]
|
||||
pub fn $name(&self, index: FileItemTreeId<$tree_id>) -> $ret {
|
||||
self.$fn(self.$field, index.0.into_raw().into_u32())
|
||||
}
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
index_item_source_maps! {
|
||||
strukt; structs_offset[Struct]; generic_item; GenericItemSourceMap<'_>,
|
||||
union; unions_offset[Union]; generic_item; GenericItemSourceMap<'_>,
|
||||
enum_generic; enum_generics_offset[Enum]; non_generic_item; &TypesSourceMap,
|
||||
variant; variants_offset[Variant]; non_generic_item; &TypesSourceMap,
|
||||
konst; consts_offset[Const]; non_generic_item; &TypesSourceMap,
|
||||
statik; statics_offset[Static]; non_generic_item; &TypesSourceMap,
|
||||
trait_generic; trait_generics_offset[Trait]; non_generic_item; &TypesSourceMap,
|
||||
trait_alias_generic; trait_alias_generics_offset[TraitAlias]; non_generic_item; &TypesSourceMap,
|
||||
impl_; impls_offset[Impl]; generic_item; GenericItemSourceMap<'_>,
|
||||
type_alias; type_aliases_offset[TypeAlias]; generic_item; GenericItemSourceMap<'_>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub enum AttrOwner {
|
||||
/// Attributes on an item.
|
||||
|
|
@ -364,7 +537,7 @@ pub trait ItemTreeNode: Clone {
|
|||
fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner;
|
||||
}
|
||||
pub trait GenericsItemTreeNode: ItemTreeNode {
|
||||
fn generic_params(&self) -> &Interned<GenericParams>;
|
||||
fn generic_params(&self) -> &Arc<GenericParams>;
|
||||
}
|
||||
|
||||
pub struct FileItemTreeId<N>(Idx<N>);
|
||||
|
|
@ -429,6 +602,16 @@ impl TreeId {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn item_tree_with_source_map(
|
||||
&self,
|
||||
db: &dyn DefDatabase,
|
||||
) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
|
||||
match self.block {
|
||||
Some(block) => db.block_item_tree_with_source_map(block),
|
||||
None => db.file_item_tree_with_source_map(self.file),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn file_id(self) -> HirFileId {
|
||||
self.file
|
||||
}
|
||||
|
|
@ -461,6 +644,13 @@ impl<N> ItemTreeId<N> {
|
|||
self.tree.item_tree(db)
|
||||
}
|
||||
|
||||
pub fn item_tree_with_source_map(
|
||||
self,
|
||||
db: &dyn DefDatabase,
|
||||
) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
|
||||
self.tree.item_tree_with_source_map(db)
|
||||
}
|
||||
|
||||
pub fn resolved<R>(self, db: &dyn DefDatabase, cb: impl FnOnce(&N) -> R) -> R
|
||||
where
|
||||
ItemTree: Index<FileItemTreeId<N>, Output = N>,
|
||||
|
|
@ -593,7 +783,7 @@ macro_rules! mod_items {
|
|||
|
||||
$(
|
||||
impl GenericsItemTreeNode for $typ {
|
||||
fn generic_params(&self) -> &Interned<GenericParams> {
|
||||
fn generic_params(&self) -> &Arc<GenericParams> {
|
||||
&self.$generic_params
|
||||
}
|
||||
}
|
||||
|
|
@ -731,17 +921,18 @@ pub struct ExternBlock {
|
|||
pub struct Function {
|
||||
pub name: Name,
|
||||
pub visibility: RawVisibilityId,
|
||||
pub explicit_generic_params: Interned<GenericParams>,
|
||||
pub explicit_generic_params: Arc<GenericParams>,
|
||||
pub abi: Option<Symbol>,
|
||||
pub params: Box<[Param]>,
|
||||
pub ret_type: Interned<TypeRef>,
|
||||
pub ret_type: TypeRefId,
|
||||
pub ast_id: FileAstId<ast::Fn>,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
pub(crate) flags: FnFlags,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Param {
|
||||
pub type_ref: Option<Interned<TypeRef>>,
|
||||
pub type_ref: Option<TypeRefId>,
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
|
|
@ -754,6 +945,7 @@ bitflags::bitflags! {
|
|||
const HAS_ASYNC_KW = 1 << 4;
|
||||
const HAS_UNSAFE_KW = 1 << 5;
|
||||
const IS_VARARGS = 1 << 6;
|
||||
const HAS_SAFE_KW = 1 << 7;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -761,26 +953,28 @@ bitflags::bitflags! {
|
|||
pub struct Struct {
|
||||
pub name: Name,
|
||||
pub visibility: RawVisibilityId,
|
||||
pub generic_params: Interned<GenericParams>,
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub fields: Box<[Field]>,
|
||||
pub shape: FieldsShape,
|
||||
pub ast_id: FileAstId<ast::Struct>,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Union {
|
||||
pub name: Name,
|
||||
pub visibility: RawVisibilityId,
|
||||
pub generic_params: Interned<GenericParams>,
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub fields: Box<[Field]>,
|
||||
pub ast_id: FileAstId<ast::Union>,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Enum {
|
||||
pub name: Name,
|
||||
pub visibility: RawVisibilityId,
|
||||
pub generic_params: Interned<GenericParams>,
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub variants: Range<FileItemTreeId<Variant>>,
|
||||
pub ast_id: FileAstId<ast::Enum>,
|
||||
}
|
||||
|
|
@ -791,6 +985,7 @@ pub struct Variant {
|
|||
pub fields: Box<[Field]>,
|
||||
pub shape: FieldsShape,
|
||||
pub ast_id: FileAstId<ast::Variant>,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
|
|
@ -804,7 +999,7 @@ pub enum FieldsShape {
|
|||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Field {
|
||||
pub name: Name,
|
||||
pub type_ref: Interned<TypeRef>,
|
||||
pub type_ref: TypeRefId,
|
||||
pub visibility: RawVisibilityId,
|
||||
}
|
||||
|
||||
|
|
@ -813,25 +1008,30 @@ pub struct Const {
|
|||
/// `None` for `const _: () = ();`
|
||||
pub name: Option<Name>,
|
||||
pub visibility: RawVisibilityId,
|
||||
pub type_ref: Interned<TypeRef>,
|
||||
pub type_ref: TypeRefId,
|
||||
pub ast_id: FileAstId<ast::Const>,
|
||||
pub has_body: bool,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Static {
|
||||
pub name: Name,
|
||||
pub visibility: RawVisibilityId,
|
||||
// TODO: use bitflags when we have more flags
|
||||
pub mutable: bool,
|
||||
pub type_ref: Interned<TypeRef>,
|
||||
pub has_safe_kw: bool,
|
||||
pub has_unsafe_kw: bool,
|
||||
pub type_ref: TypeRefId,
|
||||
pub ast_id: FileAstId<ast::Static>,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Trait {
|
||||
pub name: Name,
|
||||
pub visibility: RawVisibilityId,
|
||||
pub generic_params: Interned<GenericParams>,
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub is_auto: bool,
|
||||
pub is_unsafe: bool,
|
||||
pub items: Box<[AssocItem]>,
|
||||
|
|
@ -842,19 +1042,20 @@ pub struct Trait {
|
|||
pub struct TraitAlias {
|
||||
pub name: Name,
|
||||
pub visibility: RawVisibilityId,
|
||||
pub generic_params: Interned<GenericParams>,
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub ast_id: FileAstId<ast::TraitAlias>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Impl {
|
||||
pub generic_params: Interned<GenericParams>,
|
||||
pub target_trait: Option<Interned<TraitRef>>,
|
||||
pub self_ty: Interned<TypeRef>,
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub target_trait: Option<TraitRef>,
|
||||
pub self_ty: TypeRefId,
|
||||
pub is_negative: bool,
|
||||
pub is_unsafe: bool,
|
||||
pub items: Box<[AssocItem]>,
|
||||
pub ast_id: FileAstId<ast::Impl>,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
|
@ -862,10 +1063,11 @@ pub struct TypeAlias {
|
|||
pub name: Name,
|
||||
pub visibility: RawVisibilityId,
|
||||
/// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
|
||||
pub bounds: Box<[Interned<TypeBound>]>,
|
||||
pub generic_params: Interned<GenericParams>,
|
||||
pub type_ref: Option<Interned<TypeRef>>,
|
||||
pub bounds: Box<[TypeBound]>,
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub type_ref: Option<TypeRefId>,
|
||||
pub ast_id: FileAstId<ast::TypeAlias>,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
|
|
@ -964,6 +1166,11 @@ impl UseTree {
|
|||
self.expand_impl(None, &mut cb)
|
||||
}
|
||||
|
||||
/// The [`UseTreeKind`] of this `UseTree`.
|
||||
pub fn kind(&self) -> &UseTreeKind {
|
||||
&self.kind
|
||||
}
|
||||
|
||||
fn expand_impl(
|
||||
&self,
|
||||
prefix: Option<ModPath>,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,18 @@
|
|||
//! AST -> `ItemTree` lowering code.
|
||||
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::{cell::OnceCell, collections::hash_map::Entry};
|
||||
|
||||
use hir_expand::{mod_path::path, name::AsName, span_map::SpanMapRef, HirFileId};
|
||||
use hir_expand::{
|
||||
mod_path::path,
|
||||
name::AsName,
|
||||
span_map::{SpanMap, SpanMapRef},
|
||||
HirFileId,
|
||||
};
|
||||
use intern::{sym, Symbol};
|
||||
use la_arena::Arena;
|
||||
use rustc_hash::FxHashMap;
|
||||
use span::{AstIdMap, SyntaxContextId};
|
||||
use stdx::thin_vec::ThinVec;
|
||||
use syntax::{
|
||||
ast::{self, HasModuleItem, HasName, HasTypeBounds, IsString},
|
||||
AstNode,
|
||||
|
|
@ -18,14 +24,19 @@ use crate::{
|
|||
generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance},
|
||||
item_tree::{
|
||||
AssocItem, AttrOwner, Const, Either, Enum, ExternBlock, ExternCrate, Field, FieldParent,
|
||||
FieldsShape, FileItemTreeId, FnFlags, Function, GenericArgs, GenericModItem, Idx, Impl,
|
||||
ImportAlias, Interned, ItemTree, ItemTreeData, Macro2, MacroCall, MacroRules, Mod, ModItem,
|
||||
FieldsShape, FileItemTreeId, FnFlags, Function, GenericArgs, GenericItemSourceMapBuilder,
|
||||
GenericModItem, Idx, Impl, ImportAlias, Interned, ItemTree, ItemTreeData,
|
||||
ItemTreeSourceMaps, ItemTreeSourceMapsBuilder, Macro2, MacroCall, MacroRules, Mod, ModItem,
|
||||
ModKind, ModPath, Mutability, Name, Param, Path, Range, RawAttrs, RawIdx, RawVisibilityId,
|
||||
Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind,
|
||||
Variant,
|
||||
},
|
||||
lower::LowerCtx,
|
||||
path::AssociatedTypeBinding,
|
||||
type_ref::{LifetimeRef, TraitBoundModifier, TraitRef, TypeBound, TypeRef},
|
||||
type_ref::{
|
||||
LifetimeRef, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId,
|
||||
TypesMap, TypesSourceMap,
|
||||
},
|
||||
visibility::RawVisibility,
|
||||
LocalLifetimeParamId, LocalTypeOrConstParamId,
|
||||
};
|
||||
|
|
@ -40,7 +51,9 @@ pub(super) struct Ctx<'a> {
|
|||
source_ast_id_map: Arc<AstIdMap>,
|
||||
generic_param_attr_buffer:
|
||||
FxHashMap<Either<LocalTypeOrConstParamId, LocalLifetimeParamId>, RawAttrs>,
|
||||
body_ctx: crate::lower::LowerCtx<'a>,
|
||||
span_map: OnceCell<SpanMap>,
|
||||
file: HirFileId,
|
||||
source_maps: ItemTreeSourceMapsBuilder,
|
||||
}
|
||||
|
||||
impl<'a> Ctx<'a> {
|
||||
|
|
@ -50,22 +63,49 @@ impl<'a> Ctx<'a> {
|
|||
tree: ItemTree::default(),
|
||||
generic_param_attr_buffer: FxHashMap::default(),
|
||||
source_ast_id_map: db.ast_id_map(file),
|
||||
body_ctx: crate::lower::LowerCtx::new(db, file),
|
||||
file,
|
||||
span_map: OnceCell::new(),
|
||||
source_maps: ItemTreeSourceMapsBuilder::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn span_map(&self) -> SpanMapRef<'_> {
|
||||
self.body_ctx.span_map()
|
||||
self.span_map.get_or_init(|| self.db.span_map(self.file)).as_ref()
|
||||
}
|
||||
|
||||
pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree {
|
||||
fn body_ctx<'b, 'c>(
|
||||
&self,
|
||||
types_map: &'b mut TypesMap,
|
||||
types_source_map: &'b mut TypesSourceMap,
|
||||
) -> LowerCtx<'c>
|
||||
where
|
||||
'a: 'c,
|
||||
'b: 'c,
|
||||
{
|
||||
// FIXME: This seems a bit wasteful that if `LowerCtx` will initialize the span map we won't benefit.
|
||||
LowerCtx::with_span_map_cell(
|
||||
self.db,
|
||||
self.file,
|
||||
self.span_map.clone(),
|
||||
types_map,
|
||||
types_source_map,
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn lower_module_items(
|
||||
mut self,
|
||||
item_owner: &dyn HasModuleItem,
|
||||
) -> (ItemTree, ItemTreeSourceMaps) {
|
||||
self.tree.top_level =
|
||||
item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect();
|
||||
assert!(self.generic_param_attr_buffer.is_empty());
|
||||
self.tree
|
||||
(self.tree, self.source_maps.build())
|
||||
}
|
||||
|
||||
pub(super) fn lower_macro_stmts(mut self, stmts: ast::MacroStmts) -> ItemTree {
|
||||
pub(super) fn lower_macro_stmts(
|
||||
mut self,
|
||||
stmts: ast::MacroStmts,
|
||||
) -> (ItemTree, ItemTreeSourceMaps) {
|
||||
self.tree.top_level = stmts
|
||||
.statements()
|
||||
.filter_map(|stmt| {
|
||||
|
|
@ -96,10 +136,10 @@ impl<'a> Ctx<'a> {
|
|||
}
|
||||
|
||||
assert!(self.generic_param_attr_buffer.is_empty());
|
||||
self.tree
|
||||
(self.tree, self.source_maps.build())
|
||||
}
|
||||
|
||||
pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> ItemTree {
|
||||
pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> (ItemTree, ItemTreeSourceMaps) {
|
||||
self.tree
|
||||
.attrs
|
||||
.insert(AttrOwner::TopLevel, RawAttrs::new(self.db.upcast(), block, self.span_map()));
|
||||
|
|
@ -125,7 +165,7 @@ impl<'a> Ctx<'a> {
|
|||
}
|
||||
|
||||
assert!(self.generic_param_attr_buffer.is_empty());
|
||||
self.tree
|
||||
(self.tree, self.source_maps.build())
|
||||
}
|
||||
|
||||
fn data(&mut self) -> &mut ItemTreeData {
|
||||
|
|
@ -144,7 +184,7 @@ impl<'a> Ctx<'a> {
|
|||
ast::Item::Module(ast) => self.lower_module(ast)?.into(),
|
||||
ast::Item::Trait(ast) => self.lower_trait(ast)?.into(),
|
||||
ast::Item::TraitAlias(ast) => self.lower_trait_alias(ast)?.into(),
|
||||
ast::Item::Impl(ast) => self.lower_impl(ast)?.into(),
|
||||
ast::Item::Impl(ast) => self.lower_impl(ast).into(),
|
||||
ast::Item::Use(ast) => self.lower_use(ast)?.into(),
|
||||
ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast)?.into(),
|
||||
ast::Item::MacroCall(ast) => self.lower_macro_call(ast)?.into(),
|
||||
|
|
@ -159,12 +199,14 @@ impl<'a> Ctx<'a> {
|
|||
}
|
||||
|
||||
fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) {
|
||||
match self.tree.attrs.entry(item) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
*entry.get_mut() = entry.get().merge(attrs);
|
||||
}
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(attrs);
|
||||
if !attrs.is_empty() {
|
||||
match self.tree.attrs.entry(item) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
*entry.get_mut() = entry.get().merge(attrs);
|
||||
}
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(attrs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -190,13 +232,31 @@ impl<'a> Ctx<'a> {
|
|||
}
|
||||
|
||||
fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<FileItemTreeId<Struct>> {
|
||||
let (mut types_map, mut types_source_map) =
|
||||
(TypesMap::default(), TypesSourceMap::default());
|
||||
let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
|
||||
let visibility = self.lower_visibility(strukt);
|
||||
let name = strukt.name()?.as_name();
|
||||
let ast_id = self.source_ast_id_map.ast_id(strukt);
|
||||
let (fields, kind, attrs) = self.lower_fields(&strukt.kind());
|
||||
let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt);
|
||||
let res = Struct { name, visibility, generic_params, fields, shape: kind, ast_id };
|
||||
let (fields, kind, attrs) = self.lower_fields(&strukt.kind(), &body_ctx);
|
||||
let (generic_params, generics_source_map) =
|
||||
self.lower_generic_params(HasImplicitSelf::No, strukt);
|
||||
types_map.shrink_to_fit();
|
||||
types_source_map.shrink_to_fit();
|
||||
let res = Struct {
|
||||
name,
|
||||
visibility,
|
||||
generic_params,
|
||||
fields,
|
||||
shape: kind,
|
||||
ast_id,
|
||||
types_map: Arc::new(types_map),
|
||||
};
|
||||
let id = id(self.data().structs.alloc(res));
|
||||
self.source_maps.structs.push(GenericItemSourceMapBuilder {
|
||||
item: types_source_map,
|
||||
generics: generics_source_map,
|
||||
});
|
||||
for (idx, attr) in attrs {
|
||||
self.add_attrs(
|
||||
AttrOwner::Field(
|
||||
|
|
@ -213,6 +273,7 @@ impl<'a> Ctx<'a> {
|
|||
fn lower_fields(
|
||||
&mut self,
|
||||
strukt_kind: &ast::StructKind,
|
||||
body_ctx: &LowerCtx<'_>,
|
||||
) -> (Box<[Field]>, FieldsShape, Vec<(usize, RawAttrs)>) {
|
||||
match strukt_kind {
|
||||
ast::StructKind::Record(it) => {
|
||||
|
|
@ -220,7 +281,7 @@ impl<'a> Ctx<'a> {
|
|||
let mut attrs = vec![];
|
||||
|
||||
for (i, field) in it.fields().enumerate() {
|
||||
let data = self.lower_record_field(&field);
|
||||
let data = self.lower_record_field(&field, body_ctx);
|
||||
fields.push(data);
|
||||
let attr = RawAttrs::new(self.db.upcast(), &field, self.span_map());
|
||||
if !attr.is_empty() {
|
||||
|
|
@ -234,7 +295,7 @@ impl<'a> Ctx<'a> {
|
|||
let mut attrs = vec![];
|
||||
|
||||
for (i, field) in it.fields().enumerate() {
|
||||
let data = self.lower_tuple_field(i, &field);
|
||||
let data = self.lower_tuple_field(i, &field, body_ctx);
|
||||
fields.push(data);
|
||||
let attr = RawAttrs::new(self.db.upcast(), &field, self.span_map());
|
||||
if !attr.is_empty() {
|
||||
|
|
@ -247,35 +308,59 @@ impl<'a> Ctx<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_record_field(&mut self, field: &ast::RecordField) -> Field {
|
||||
fn lower_record_field(&mut self, field: &ast::RecordField, body_ctx: &LowerCtx<'_>) -> Field {
|
||||
let name = match field.name() {
|
||||
Some(name) => name.as_name(),
|
||||
None => Name::missing(),
|
||||
};
|
||||
let visibility = self.lower_visibility(field);
|
||||
let type_ref = self.lower_type_ref_opt(field.ty());
|
||||
let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
|
||||
|
||||
Field { name, type_ref, visibility }
|
||||
}
|
||||
|
||||
fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleField) -> Field {
|
||||
fn lower_tuple_field(
|
||||
&mut self,
|
||||
idx: usize,
|
||||
field: &ast::TupleField,
|
||||
body_ctx: &LowerCtx<'_>,
|
||||
) -> Field {
|
||||
let name = Name::new_tuple_field(idx);
|
||||
let visibility = self.lower_visibility(field);
|
||||
let type_ref = self.lower_type_ref_opt(field.ty());
|
||||
let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
|
||||
Field { name, type_ref, visibility }
|
||||
}
|
||||
|
||||
fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
|
||||
let (mut types_map, mut types_source_map) =
|
||||
(TypesMap::default(), TypesSourceMap::default());
|
||||
let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
|
||||
let visibility = self.lower_visibility(union);
|
||||
let name = union.name()?.as_name();
|
||||
let ast_id = self.source_ast_id_map.ast_id(union);
|
||||
let (fields, _, attrs) = match union.record_field_list() {
|
||||
Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)),
|
||||
Some(record_field_list) => {
|
||||
self.lower_fields(&StructKind::Record(record_field_list), &body_ctx)
|
||||
}
|
||||
None => (Box::default(), FieldsShape::Record, Vec::default()),
|
||||
};
|
||||
let generic_params = self.lower_generic_params(HasImplicitSelf::No, union);
|
||||
let res = Union { name, visibility, generic_params, fields, ast_id };
|
||||
let (generic_params, generics_source_map) =
|
||||
self.lower_generic_params(HasImplicitSelf::No, union);
|
||||
types_map.shrink_to_fit();
|
||||
types_source_map.shrink_to_fit();
|
||||
let res = Union {
|
||||
name,
|
||||
visibility,
|
||||
generic_params,
|
||||
fields,
|
||||
ast_id,
|
||||
types_map: Arc::new(types_map),
|
||||
};
|
||||
let id = id(self.data().unions.alloc(res));
|
||||
self.source_maps.unions.push(GenericItemSourceMapBuilder {
|
||||
item: types_source_map,
|
||||
generics: generics_source_map,
|
||||
});
|
||||
for (idx, attr) in attrs {
|
||||
self.add_attrs(
|
||||
AttrOwner::Field(
|
||||
|
|
@ -299,9 +384,11 @@ impl<'a> Ctx<'a> {
|
|||
FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx())
|
||||
}
|
||||
};
|
||||
let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_);
|
||||
let (generic_params, generics_source_map) =
|
||||
self.lower_generic_params(HasImplicitSelf::No, enum_);
|
||||
let res = Enum { name, visibility, generic_params, variants, ast_id };
|
||||
let id = id(self.data().enums.alloc(res));
|
||||
self.source_maps.enum_generics.push(generics_source_map);
|
||||
self.write_generic_params_attributes(id.into());
|
||||
Some(id)
|
||||
}
|
||||
|
|
@ -320,14 +407,20 @@ impl<'a> Ctx<'a> {
|
|||
}
|
||||
|
||||
fn lower_variant(&mut self, variant: &ast::Variant) -> Idx<Variant> {
|
||||
let (mut types_map, mut types_source_map) =
|
||||
(TypesMap::default(), TypesSourceMap::default());
|
||||
let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
|
||||
let name = match variant.name() {
|
||||
Some(name) => name.as_name(),
|
||||
None => Name::missing(),
|
||||
};
|
||||
let (fields, kind, attrs) = self.lower_fields(&variant.kind());
|
||||
let (fields, kind, attrs) = self.lower_fields(&variant.kind(), &body_ctx);
|
||||
let ast_id = self.source_ast_id_map.ast_id(variant);
|
||||
let res = Variant { name, fields, shape: kind, ast_id };
|
||||
types_map.shrink_to_fit();
|
||||
types_source_map.shrink_to_fit();
|
||||
let res = Variant { name, fields, shape: kind, ast_id, types_map: Arc::new(types_map) };
|
||||
let id = self.data().variants.alloc(res);
|
||||
self.source_maps.variants.push(types_source_map);
|
||||
for (idx, attr) in attrs {
|
||||
self.add_attrs(
|
||||
AttrOwner::Field(
|
||||
|
|
@ -341,6 +434,10 @@ impl<'a> Ctx<'a> {
|
|||
}
|
||||
|
||||
fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>> {
|
||||
let (mut types_map, mut types_source_map) =
|
||||
(TypesMap::default(), TypesSourceMap::default());
|
||||
let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
|
||||
|
||||
let visibility = self.lower_visibility(func);
|
||||
let name = func.name()?.as_name();
|
||||
|
||||
|
|
@ -360,27 +457,31 @@ impl<'a> Ctx<'a> {
|
|||
RawAttrs::new(self.db.upcast(), &self_param, self.span_map()),
|
||||
);
|
||||
let self_type = match self_param.ty() {
|
||||
Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
|
||||
Some(type_ref) => TypeRef::from_ast(&body_ctx, type_ref),
|
||||
None => {
|
||||
let self_type =
|
||||
TypeRef::Path(Name::new_symbol_root(sym::Self_.clone()).into());
|
||||
let self_type = body_ctx.alloc_type_ref_desugared(TypeRef::Path(
|
||||
Name::new_symbol_root(sym::Self_.clone()).into(),
|
||||
));
|
||||
match self_param.kind() {
|
||||
ast::SelfParamKind::Owned => self_type,
|
||||
ast::SelfParamKind::Ref => TypeRef::Reference(
|
||||
Box::new(self_type),
|
||||
self_param.lifetime().as_ref().map(LifetimeRef::new),
|
||||
Mutability::Shared,
|
||||
ast::SelfParamKind::Ref => body_ctx.alloc_type_ref_desugared(
|
||||
TypeRef::Reference(Box::new(RefType {
|
||||
ty: self_type,
|
||||
lifetime: self_param.lifetime().as_ref().map(LifetimeRef::new),
|
||||
mutability: Mutability::Shared,
|
||||
})),
|
||||
),
|
||||
ast::SelfParamKind::MutRef => TypeRef::Reference(
|
||||
Box::new(self_type),
|
||||
self_param.lifetime().as_ref().map(LifetimeRef::new),
|
||||
Mutability::Mut,
|
||||
ast::SelfParamKind::MutRef => body_ctx.alloc_type_ref_desugared(
|
||||
TypeRef::Reference(Box::new(RefType {
|
||||
ty: self_type,
|
||||
lifetime: self_param.lifetime().as_ref().map(LifetimeRef::new),
|
||||
mutability: Mutability::Mut,
|
||||
})),
|
||||
),
|
||||
}
|
||||
}
|
||||
};
|
||||
let type_ref = Interned::new(self_type);
|
||||
params.push(Param { type_ref: Some(type_ref) });
|
||||
params.push(Param { type_ref: Some(self_type) });
|
||||
has_self_param = true;
|
||||
}
|
||||
for param in param_list.params() {
|
||||
|
|
@ -391,9 +492,8 @@ impl<'a> Ctx<'a> {
|
|||
Param { type_ref: None }
|
||||
}
|
||||
None => {
|
||||
let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty());
|
||||
let ty = Interned::new(type_ref);
|
||||
Param { type_ref: Some(ty) }
|
||||
let type_ref = TypeRef::from_ast_opt(&body_ctx, param.ty());
|
||||
Param { type_ref: Some(type_ref) }
|
||||
}
|
||||
};
|
||||
params.push(param);
|
||||
|
|
@ -402,17 +502,17 @@ impl<'a> Ctx<'a> {
|
|||
|
||||
let ret_type = match func.ret_type() {
|
||||
Some(rt) => match rt.ty() {
|
||||
Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
|
||||
None if rt.thin_arrow_token().is_some() => TypeRef::Error,
|
||||
None => TypeRef::unit(),
|
||||
Some(type_ref) => TypeRef::from_ast(&body_ctx, type_ref),
|
||||
None if rt.thin_arrow_token().is_some() => body_ctx.alloc_error_type(),
|
||||
None => body_ctx.alloc_type_ref_desugared(TypeRef::unit()),
|
||||
},
|
||||
None => TypeRef::unit(),
|
||||
None => body_ctx.alloc_type_ref_desugared(TypeRef::unit()),
|
||||
};
|
||||
|
||||
let ret_type = if func.async_token().is_some() {
|
||||
let future_impl = desugar_future_path(ret_type);
|
||||
let ty_bound = Interned::new(TypeBound::Path(future_impl, TraitBoundModifier::None));
|
||||
TypeRef::ImplTrait(vec![ty_bound])
|
||||
let ty_bound = TypeBound::Path(future_impl, TraitBoundModifier::None);
|
||||
body_ctx.alloc_type_ref_desugared(TypeRef::ImplTrait(ThinVec::from_iter([ty_bound])))
|
||||
} else {
|
||||
ret_type
|
||||
};
|
||||
|
|
@ -440,22 +540,34 @@ impl<'a> Ctx<'a> {
|
|||
if func.unsafe_token().is_some() {
|
||||
flags |= FnFlags::HAS_UNSAFE_KW;
|
||||
}
|
||||
if func.safe_token().is_some() {
|
||||
flags |= FnFlags::HAS_SAFE_KW;
|
||||
}
|
||||
if has_var_args {
|
||||
flags |= FnFlags::IS_VARARGS;
|
||||
}
|
||||
|
||||
types_map.shrink_to_fit();
|
||||
types_source_map.shrink_to_fit();
|
||||
let (generic_params, generics_source_map) =
|
||||
self.lower_generic_params(HasImplicitSelf::No, func);
|
||||
let res = Function {
|
||||
name,
|
||||
visibility,
|
||||
explicit_generic_params: self.lower_generic_params(HasImplicitSelf::No, func),
|
||||
explicit_generic_params: generic_params,
|
||||
abi,
|
||||
params: params.into_boxed_slice(),
|
||||
ret_type: Interned::new(ret_type),
|
||||
ret_type,
|
||||
ast_id,
|
||||
types_map: Arc::new(types_map),
|
||||
flags,
|
||||
};
|
||||
|
||||
let id = id(self.data().functions.alloc(res));
|
||||
self.source_maps.functions.push(GenericItemSourceMapBuilder {
|
||||
item: types_source_map,
|
||||
generics: generics_source_map,
|
||||
});
|
||||
for (idx, attr) in attrs {
|
||||
self.add_attrs(AttrOwner::Param(id, Idx::from_raw(RawIdx::from_u32(idx as u32))), attr);
|
||||
}
|
||||
|
|
@ -467,34 +579,82 @@ impl<'a> Ctx<'a> {
|
|||
&mut self,
|
||||
type_alias: &ast::TypeAlias,
|
||||
) -> Option<FileItemTreeId<TypeAlias>> {
|
||||
let (mut types_map, mut types_source_map) =
|
||||
(TypesMap::default(), TypesSourceMap::default());
|
||||
let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
|
||||
let name = type_alias.name()?.as_name();
|
||||
let type_ref = type_alias.ty().map(|it| self.lower_type_ref(&it));
|
||||
let type_ref = type_alias.ty().map(|it| TypeRef::from_ast(&body_ctx, it));
|
||||
let visibility = self.lower_visibility(type_alias);
|
||||
let bounds = self.lower_type_bounds(type_alias);
|
||||
let bounds = self.lower_type_bounds(type_alias, &body_ctx);
|
||||
let ast_id = self.source_ast_id_map.ast_id(type_alias);
|
||||
let generic_params = self.lower_generic_params(HasImplicitSelf::No, type_alias);
|
||||
let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id };
|
||||
let (generic_params, generics_source_map) =
|
||||
self.lower_generic_params(HasImplicitSelf::No, type_alias);
|
||||
types_map.shrink_to_fit();
|
||||
types_source_map.shrink_to_fit();
|
||||
let res = TypeAlias {
|
||||
name,
|
||||
visibility,
|
||||
bounds,
|
||||
generic_params,
|
||||
type_ref,
|
||||
ast_id,
|
||||
types_map: Arc::new(types_map),
|
||||
};
|
||||
let id = id(self.data().type_aliases.alloc(res));
|
||||
self.source_maps.type_aliases.push(GenericItemSourceMapBuilder {
|
||||
item: types_source_map,
|
||||
generics: generics_source_map,
|
||||
});
|
||||
self.write_generic_params_attributes(id.into());
|
||||
Some(id)
|
||||
}
|
||||
|
||||
fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Static>> {
|
||||
let (mut types_map, mut types_source_map) =
|
||||
(TypesMap::default(), TypesSourceMap::default());
|
||||
let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
|
||||
let name = static_.name()?.as_name();
|
||||
let type_ref = self.lower_type_ref_opt(static_.ty());
|
||||
let type_ref = TypeRef::from_ast_opt(&body_ctx, static_.ty());
|
||||
let visibility = self.lower_visibility(static_);
|
||||
let mutable = static_.mut_token().is_some();
|
||||
let has_safe_kw = static_.safe_token().is_some();
|
||||
let has_unsafe_kw = static_.unsafe_token().is_some();
|
||||
let ast_id = self.source_ast_id_map.ast_id(static_);
|
||||
let res = Static { name, visibility, mutable, type_ref, ast_id };
|
||||
types_map.shrink_to_fit();
|
||||
types_source_map.shrink_to_fit();
|
||||
let res = Static {
|
||||
name,
|
||||
visibility,
|
||||
mutable,
|
||||
type_ref,
|
||||
ast_id,
|
||||
has_safe_kw,
|
||||
has_unsafe_kw,
|
||||
types_map: Arc::new(types_map),
|
||||
};
|
||||
self.source_maps.statics.push(types_source_map);
|
||||
Some(id(self.data().statics.alloc(res)))
|
||||
}
|
||||
|
||||
fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId<Const> {
|
||||
let (mut types_map, mut types_source_map) =
|
||||
(TypesMap::default(), TypesSourceMap::default());
|
||||
let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
|
||||
let name = konst.name().map(|it| it.as_name());
|
||||
let type_ref = self.lower_type_ref_opt(konst.ty());
|
||||
let type_ref = TypeRef::from_ast_opt(&body_ctx, konst.ty());
|
||||
let visibility = self.lower_visibility(konst);
|
||||
let ast_id = self.source_ast_id_map.ast_id(konst);
|
||||
let res = Const { name, visibility, type_ref, ast_id, has_body: konst.body().is_some() };
|
||||
types_map.shrink_to_fit();
|
||||
types_source_map.shrink_to_fit();
|
||||
let res = Const {
|
||||
name,
|
||||
visibility,
|
||||
type_ref,
|
||||
ast_id,
|
||||
has_body: konst.body().is_some(),
|
||||
types_map: Arc::new(types_map),
|
||||
};
|
||||
self.source_maps.consts.push(types_source_map);
|
||||
id(self.data().consts.alloc(res))
|
||||
}
|
||||
|
||||
|
|
@ -533,10 +693,11 @@ impl<'a> Ctx<'a> {
|
|||
.filter_map(|item_node| self.lower_assoc_item(&item_node))
|
||||
.collect();
|
||||
|
||||
let generic_params =
|
||||
let (generic_params, generics_source_map) =
|
||||
self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def);
|
||||
let def = Trait { name, visibility, generic_params, is_auto, is_unsafe, items, ast_id };
|
||||
let id = id(self.data().traits.alloc(def));
|
||||
self.source_maps.trait_generics.push(generics_source_map);
|
||||
self.write_generic_params_attributes(id.into());
|
||||
Some(id)
|
||||
}
|
||||
|
|
@ -548,24 +709,29 @@ impl<'a> Ctx<'a> {
|
|||
let name = trait_alias_def.name()?.as_name();
|
||||
let visibility = self.lower_visibility(trait_alias_def);
|
||||
let ast_id = self.source_ast_id_map.ast_id(trait_alias_def);
|
||||
let generic_params = self.lower_generic_params(
|
||||
let (generic_params, generics_source_map) = self.lower_generic_params(
|
||||
HasImplicitSelf::Yes(trait_alias_def.type_bound_list()),
|
||||
trait_alias_def,
|
||||
);
|
||||
|
||||
let alias = TraitAlias { name, visibility, generic_params, ast_id };
|
||||
let id = id(self.data().trait_aliases.alloc(alias));
|
||||
self.source_maps.trait_alias_generics.push(generics_source_map);
|
||||
self.write_generic_params_attributes(id.into());
|
||||
Some(id)
|
||||
}
|
||||
|
||||
fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> {
|
||||
fn lower_impl(&mut self, impl_def: &ast::Impl) -> FileItemTreeId<Impl> {
|
||||
let (mut types_map, mut types_source_map) =
|
||||
(TypesMap::default(), TypesSourceMap::default());
|
||||
let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
|
||||
|
||||
let ast_id = self.source_ast_id_map.ast_id(impl_def);
|
||||
// FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl
|
||||
// as if it was an non-trait impl. Ideally we want to create a unique missing ref that only
|
||||
// equals itself.
|
||||
let self_ty = self.lower_type_ref(&impl_def.self_ty()?);
|
||||
let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr));
|
||||
let self_ty = TypeRef::from_ast_opt(&body_ctx, impl_def.self_ty());
|
||||
let target_trait = impl_def.trait_().and_then(|tr| TraitRef::from_ast(&body_ctx, tr));
|
||||
let is_negative = impl_def.excl_token().is_some();
|
||||
let is_unsafe = impl_def.unsafe_token().is_some();
|
||||
|
||||
|
|
@ -578,12 +744,27 @@ impl<'a> Ctx<'a> {
|
|||
.collect();
|
||||
// Note that trait impls don't get implicit `Self` unlike traits, because here they are a
|
||||
// type alias rather than a type parameter, so this is handled by the resolver.
|
||||
let generic_params = self.lower_generic_params(HasImplicitSelf::No, impl_def);
|
||||
let res =
|
||||
Impl { generic_params, target_trait, self_ty, is_negative, is_unsafe, items, ast_id };
|
||||
let (generic_params, generics_source_map) =
|
||||
self.lower_generic_params(HasImplicitSelf::No, impl_def);
|
||||
types_map.shrink_to_fit();
|
||||
types_source_map.shrink_to_fit();
|
||||
let res = Impl {
|
||||
generic_params,
|
||||
target_trait,
|
||||
self_ty,
|
||||
is_negative,
|
||||
is_unsafe,
|
||||
items,
|
||||
ast_id,
|
||||
types_map: Arc::new(types_map),
|
||||
};
|
||||
let id = id(self.data().impls.alloc(res));
|
||||
self.source_maps.impls.push(GenericItemSourceMapBuilder {
|
||||
item: types_source_map,
|
||||
generics: generics_source_map,
|
||||
});
|
||||
self.write_generic_params_attributes(id.into());
|
||||
Some(id)
|
||||
id
|
||||
}
|
||||
|
||||
fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Use>> {
|
||||
|
|
@ -686,14 +867,17 @@ impl<'a> Ctx<'a> {
|
|||
&mut self,
|
||||
has_implicit_self: HasImplicitSelf,
|
||||
node: &dyn ast::HasGenericParams,
|
||||
) -> Interned<GenericParams> {
|
||||
) -> (Arc<GenericParams>, TypesSourceMap) {
|
||||
let (mut types_map, mut types_source_map) =
|
||||
(TypesMap::default(), TypesSourceMap::default());
|
||||
let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
|
||||
debug_assert!(self.generic_param_attr_buffer.is_empty(),);
|
||||
let add_param_attrs = |item: Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
|
||||
param| {
|
||||
let attrs = RawAttrs::new(self.db.upcast(), ¶m, self.body_ctx.span_map());
|
||||
let attrs = RawAttrs::new(self.db.upcast(), ¶m, body_ctx.span_map());
|
||||
debug_assert!(self.generic_param_attr_buffer.insert(item, attrs).is_none());
|
||||
};
|
||||
self.body_ctx.take_impl_traits_bounds();
|
||||
body_ctx.take_impl_traits_bounds();
|
||||
let mut generics = GenericParamsCollector::default();
|
||||
|
||||
if let HasImplicitSelf::Yes(bounds) = has_implicit_self {
|
||||
|
|
@ -709,23 +893,29 @@ impl<'a> Ctx<'a> {
|
|||
// add super traits as bounds on Self
|
||||
// i.e., `trait Foo: Bar` is equivalent to `trait Foo where Self: Bar`
|
||||
generics.fill_bounds(
|
||||
&self.body_ctx,
|
||||
&body_ctx,
|
||||
bounds,
|
||||
Either::Left(TypeRef::Path(Name::new_symbol_root(sym::Self_.clone()).into())),
|
||||
Either::Left(body_ctx.alloc_type_ref_desugared(TypeRef::Path(
|
||||
Name::new_symbol_root(sym::Self_.clone()).into(),
|
||||
))),
|
||||
);
|
||||
}
|
||||
|
||||
generics.fill(&self.body_ctx, node, add_param_attrs);
|
||||
generics.fill(&body_ctx, node, add_param_attrs);
|
||||
|
||||
Interned::new(generics.finish())
|
||||
let generics = generics.finish(types_map, &mut types_source_map);
|
||||
(generics, types_source_map)
|
||||
}
|
||||
|
||||
fn lower_type_bounds(&mut self, node: &dyn ast::HasTypeBounds) -> Box<[Interned<TypeBound>]> {
|
||||
fn lower_type_bounds(
|
||||
&mut self,
|
||||
node: &dyn ast::HasTypeBounds,
|
||||
body_ctx: &LowerCtx<'_>,
|
||||
) -> Box<[TypeBound]> {
|
||||
match node.type_bound_list() {
|
||||
Some(bound_list) => bound_list
|
||||
.bounds()
|
||||
.map(|it| Interned::new(TypeBound::from_ast(&self.body_ctx, it)))
|
||||
.collect(),
|
||||
Some(bound_list) => {
|
||||
bound_list.bounds().map(|it| TypeBound::from_ast(body_ctx, it)).collect()
|
||||
}
|
||||
None => Box::default(),
|
||||
}
|
||||
}
|
||||
|
|
@ -737,23 +927,6 @@ impl<'a> Ctx<'a> {
|
|||
self.data().vis.alloc(vis)
|
||||
}
|
||||
|
||||
fn lower_trait_ref(&mut self, trait_ref: &ast::Type) -> Option<Interned<TraitRef>> {
|
||||
let trait_ref = TraitRef::from_ast(&self.body_ctx, trait_ref.clone())?;
|
||||
Some(Interned::new(trait_ref))
|
||||
}
|
||||
|
||||
fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Interned<TypeRef> {
|
||||
let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone());
|
||||
Interned::new(tyref)
|
||||
}
|
||||
|
||||
fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Interned<TypeRef> {
|
||||
match type_ref.map(|ty| self.lower_type_ref(&ty)) {
|
||||
Some(it) => it,
|
||||
None => Interned::new(TypeRef::Error),
|
||||
}
|
||||
}
|
||||
|
||||
fn next_variant_idx(&self) -> Idx<Variant> {
|
||||
Idx::from_raw(RawIdx::from(
|
||||
self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32),
|
||||
|
|
@ -761,7 +934,7 @@ impl<'a> Ctx<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn desugar_future_path(orig: TypeRef) -> Path {
|
||||
fn desugar_future_path(orig: TypeRefId) -> Path {
|
||||
let path = path![core::future::Future];
|
||||
let mut generic_args: Vec<_> =
|
||||
std::iter::repeat(None).take(path.segments().len() - 1).collect();
|
||||
|
|
@ -771,10 +944,7 @@ fn desugar_future_path(orig: TypeRef) -> Path {
|
|||
type_ref: Some(orig),
|
||||
bounds: Box::default(),
|
||||
};
|
||||
generic_args.push(Some(Interned::new(GenericArgs {
|
||||
bindings: Box::new([binding]),
|
||||
..GenericArgs::empty()
|
||||
})));
|
||||
generic_args.push(Some(GenericArgs { bindings: Box::new([binding]), ..GenericArgs::empty() }));
|
||||
|
||||
Path::from_known_path(path, generic_args)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,11 +10,12 @@ use crate::{
|
|||
item_tree::{
|
||||
AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldParent,
|
||||
FieldsShape, FileItemTreeId, FnFlags, Function, GenericModItem, GenericParams, Impl,
|
||||
Interned, ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, Path,
|
||||
RawAttrs, RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound,
|
||||
TypeRef, Union, Use, UseTree, UseTreeKind, Variant,
|
||||
ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, Path, RawAttrs,
|
||||
RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound, Union, Use,
|
||||
UseTree, UseTreeKind, Variant,
|
||||
},
|
||||
pretty::{print_path, print_type_bounds, print_type_ref},
|
||||
type_ref::{TypeRefId, TypesMap},
|
||||
visibility::RawVisibility,
|
||||
};
|
||||
|
||||
|
|
@ -121,7 +122,13 @@ impl Printer<'_> {
|
|||
};
|
||||
}
|
||||
|
||||
fn print_fields(&mut self, parent: FieldParent, kind: FieldsShape, fields: &[Field]) {
|
||||
fn print_fields(
|
||||
&mut self,
|
||||
parent: FieldParent,
|
||||
kind: FieldsShape,
|
||||
fields: &[Field],
|
||||
map: &TypesMap,
|
||||
) {
|
||||
let edition = self.edition;
|
||||
match kind {
|
||||
FieldsShape::Record => {
|
||||
|
|
@ -135,7 +142,7 @@ impl Printer<'_> {
|
|||
);
|
||||
this.print_visibility(*visibility);
|
||||
w!(this, "{}: ", name.display(self.db.upcast(), edition));
|
||||
this.print_type_ref(type_ref);
|
||||
this.print_type_ref(*type_ref, map);
|
||||
wln!(this, ",");
|
||||
}
|
||||
});
|
||||
|
|
@ -151,7 +158,7 @@ impl Printer<'_> {
|
|||
);
|
||||
this.print_visibility(*visibility);
|
||||
w!(this, "{}: ", name.display(self.db.upcast(), edition));
|
||||
this.print_type_ref(type_ref);
|
||||
this.print_type_ref(*type_ref, map);
|
||||
wln!(this, ",");
|
||||
}
|
||||
});
|
||||
|
|
@ -167,20 +174,21 @@ impl Printer<'_> {
|
|||
kind: FieldsShape,
|
||||
fields: &[Field],
|
||||
params: &GenericParams,
|
||||
map: &TypesMap,
|
||||
) {
|
||||
match kind {
|
||||
FieldsShape::Record => {
|
||||
if self.print_where_clause(params) {
|
||||
wln!(self);
|
||||
}
|
||||
self.print_fields(parent, kind, fields);
|
||||
self.print_fields(parent, kind, fields, map);
|
||||
}
|
||||
FieldsShape::Unit => {
|
||||
self.print_where_clause(params);
|
||||
self.print_fields(parent, kind, fields);
|
||||
self.print_fields(parent, kind, fields, map);
|
||||
}
|
||||
FieldsShape::Tuple => {
|
||||
self.print_fields(parent, kind, fields);
|
||||
self.print_fields(parent, kind, fields, map);
|
||||
self.print_where_clause(params);
|
||||
}
|
||||
}
|
||||
|
|
@ -262,6 +270,7 @@ impl Printer<'_> {
|
|||
params,
|
||||
ret_type,
|
||||
ast_id,
|
||||
types_map,
|
||||
flags,
|
||||
} = &self.tree[it];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
|
|
@ -278,6 +287,9 @@ impl Printer<'_> {
|
|||
if flags.contains(FnFlags::HAS_UNSAFE_KW) {
|
||||
w!(self, "unsafe ");
|
||||
}
|
||||
if flags.contains(FnFlags::HAS_SAFE_KW) {
|
||||
w!(self, "safe ");
|
||||
}
|
||||
if let Some(abi) = abi {
|
||||
w!(self, "extern \"{}\" ", abi);
|
||||
}
|
||||
|
|
@ -295,7 +307,7 @@ impl Printer<'_> {
|
|||
w!(this, "self: ");
|
||||
}
|
||||
if let Some(type_ref) = type_ref {
|
||||
this.print_type_ref(type_ref);
|
||||
this.print_type_ref(*type_ref, types_map);
|
||||
} else {
|
||||
wln!(this, "...");
|
||||
}
|
||||
|
|
@ -304,7 +316,7 @@ impl Printer<'_> {
|
|||
});
|
||||
}
|
||||
w!(self, ") -> ");
|
||||
self.print_type_ref(ret_type);
|
||||
self.print_type_ref(*ret_type, types_map);
|
||||
self.print_where_clause(explicit_generic_params);
|
||||
if flags.contains(FnFlags::HAS_BODY) {
|
||||
wln!(self, " {{ ... }}");
|
||||
|
|
@ -313,8 +325,15 @@ impl Printer<'_> {
|
|||
}
|
||||
}
|
||||
ModItem::Struct(it) => {
|
||||
let Struct { visibility, name, fields, shape: kind, generic_params, ast_id } =
|
||||
&self.tree[it];
|
||||
let Struct {
|
||||
visibility,
|
||||
name,
|
||||
fields,
|
||||
shape: kind,
|
||||
generic_params,
|
||||
ast_id,
|
||||
types_map,
|
||||
} = &self.tree[it];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
w!(self, "struct {}", name.display(self.db.upcast(), self.edition));
|
||||
|
|
@ -324,6 +343,7 @@ impl Printer<'_> {
|
|||
*kind,
|
||||
fields,
|
||||
generic_params,
|
||||
types_map,
|
||||
);
|
||||
if matches!(kind, FieldsShape::Record) {
|
||||
wln!(self);
|
||||
|
|
@ -332,7 +352,8 @@ impl Printer<'_> {
|
|||
}
|
||||
}
|
||||
ModItem::Union(it) => {
|
||||
let Union { name, visibility, fields, generic_params, ast_id } = &self.tree[it];
|
||||
let Union { name, visibility, fields, generic_params, ast_id, types_map } =
|
||||
&self.tree[it];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
w!(self, "union {}", name.display(self.db.upcast(), self.edition));
|
||||
|
|
@ -342,6 +363,7 @@ impl Printer<'_> {
|
|||
FieldsShape::Record,
|
||||
fields,
|
||||
generic_params,
|
||||
types_map,
|
||||
);
|
||||
wln!(self);
|
||||
}
|
||||
|
|
@ -355,18 +377,20 @@ impl Printer<'_> {
|
|||
let edition = self.edition;
|
||||
self.indented(|this| {
|
||||
for variant in FileItemTreeId::range_iter(variants.clone()) {
|
||||
let Variant { name, fields, shape: kind, ast_id } = &this.tree[variant];
|
||||
let Variant { name, fields, shape: kind, ast_id, types_map } =
|
||||
&this.tree[variant];
|
||||
this.print_ast_id(ast_id.erase());
|
||||
this.print_attrs_of(variant, "\n");
|
||||
w!(this, "{}", name.display(self.db.upcast(), edition));
|
||||
this.print_fields(FieldParent::Variant(variant), *kind, fields);
|
||||
this.print_fields(FieldParent::Variant(variant), *kind, fields, types_map);
|
||||
wln!(this, ",");
|
||||
}
|
||||
});
|
||||
wln!(self, "}}");
|
||||
}
|
||||
ModItem::Const(it) => {
|
||||
let Const { name, visibility, type_ref, ast_id, has_body: _ } = &self.tree[it];
|
||||
let Const { name, visibility, type_ref, ast_id, has_body: _, types_map } =
|
||||
&self.tree[it];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
w!(self, "const ");
|
||||
|
|
@ -375,19 +399,34 @@ impl Printer<'_> {
|
|||
None => w!(self, "_"),
|
||||
}
|
||||
w!(self, ": ");
|
||||
self.print_type_ref(type_ref);
|
||||
self.print_type_ref(*type_ref, types_map);
|
||||
wln!(self, " = _;");
|
||||
}
|
||||
ModItem::Static(it) => {
|
||||
let Static { name, visibility, mutable, type_ref, ast_id } = &self.tree[it];
|
||||
let Static {
|
||||
name,
|
||||
visibility,
|
||||
mutable,
|
||||
type_ref,
|
||||
ast_id,
|
||||
has_safe_kw,
|
||||
has_unsafe_kw,
|
||||
types_map,
|
||||
} = &self.tree[it];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
if *has_safe_kw {
|
||||
w!(self, "safe ");
|
||||
}
|
||||
if *has_unsafe_kw {
|
||||
w!(self, "unsafe ");
|
||||
}
|
||||
w!(self, "static ");
|
||||
if *mutable {
|
||||
w!(self, "mut ");
|
||||
}
|
||||
w!(self, "{}: ", name.display(self.db.upcast(), self.edition));
|
||||
self.print_type_ref(type_ref);
|
||||
self.print_type_ref(*type_ref, types_map);
|
||||
w!(self, " = _;");
|
||||
wln!(self);
|
||||
}
|
||||
|
|
@ -432,6 +471,7 @@ impl Printer<'_> {
|
|||
items,
|
||||
generic_params,
|
||||
ast_id,
|
||||
types_map,
|
||||
} = &self.tree[it];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
if *is_unsafe {
|
||||
|
|
@ -444,10 +484,10 @@ impl Printer<'_> {
|
|||
w!(self, "!");
|
||||
}
|
||||
if let Some(tr) = target_trait {
|
||||
self.print_path(&tr.path);
|
||||
self.print_path(&tr.path, types_map);
|
||||
w!(self, " for ");
|
||||
}
|
||||
self.print_type_ref(self_ty);
|
||||
self.print_type_ref(*self_ty, types_map);
|
||||
self.print_where_clause_and_opening_brace(generic_params);
|
||||
self.indented(|this| {
|
||||
for item in &**items {
|
||||
|
|
@ -457,19 +497,26 @@ impl Printer<'_> {
|
|||
wln!(self, "}}");
|
||||
}
|
||||
ModItem::TypeAlias(it) => {
|
||||
let TypeAlias { name, visibility, bounds, type_ref, generic_params, ast_id } =
|
||||
&self.tree[it];
|
||||
let TypeAlias {
|
||||
name,
|
||||
visibility,
|
||||
bounds,
|
||||
type_ref,
|
||||
generic_params,
|
||||
ast_id,
|
||||
types_map,
|
||||
} = &self.tree[it];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
w!(self, "type {}", name.display(self.db.upcast(), self.edition));
|
||||
self.print_generic_params(generic_params, it.into());
|
||||
if !bounds.is_empty() {
|
||||
w!(self, ": ");
|
||||
self.print_type_bounds(bounds);
|
||||
self.print_type_bounds(bounds, types_map);
|
||||
}
|
||||
if let Some(ty) = type_ref {
|
||||
w!(self, " = ");
|
||||
self.print_type_ref(ty);
|
||||
self.print_type_ref(*ty, types_map);
|
||||
}
|
||||
self.print_where_clause(generic_params);
|
||||
w!(self, ";");
|
||||
|
|
@ -526,19 +573,19 @@ impl Printer<'_> {
|
|||
self.blank();
|
||||
}
|
||||
|
||||
fn print_type_ref(&mut self, type_ref: &TypeRef) {
|
||||
fn print_type_ref(&mut self, type_ref: TypeRefId, map: &TypesMap) {
|
||||
let edition = self.edition;
|
||||
print_type_ref(self.db, type_ref, self, edition).unwrap();
|
||||
print_type_ref(self.db, type_ref, map, self, edition).unwrap();
|
||||
}
|
||||
|
||||
fn print_type_bounds(&mut self, bounds: &[Interned<TypeBound>]) {
|
||||
fn print_type_bounds(&mut self, bounds: &[TypeBound], map: &TypesMap) {
|
||||
let edition = self.edition;
|
||||
print_type_bounds(self.db, bounds, self, edition).unwrap();
|
||||
print_type_bounds(self.db, bounds, map, self, edition).unwrap();
|
||||
}
|
||||
|
||||
fn print_path(&mut self, path: &Path) {
|
||||
fn print_path(&mut self, path: &Path, map: &TypesMap) {
|
||||
let edition = self.edition;
|
||||
print_path(self.db, path, self, edition).unwrap();
|
||||
print_path(self.db, path, map, self, edition).unwrap();
|
||||
}
|
||||
|
||||
fn print_generic_params(&mut self, params: &GenericParams, parent: GenericModItem) {
|
||||
|
|
@ -569,7 +616,7 @@ impl Printer<'_> {
|
|||
},
|
||||
TypeOrConstParamData::ConstParamData(konst) => {
|
||||
w!(self, "const {}: ", konst.name.display(self.db.upcast(), self.edition));
|
||||
self.print_type_ref(&konst.ty);
|
||||
self.print_type_ref(konst.ty, ¶ms.types_map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -623,14 +670,16 @@ impl Printer<'_> {
|
|||
};
|
||||
|
||||
match target {
|
||||
WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
|
||||
WherePredicateTypeTarget::TypeRef(ty) => {
|
||||
this.print_type_ref(*ty, ¶ms.types_map)
|
||||
}
|
||||
WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() {
|
||||
Some(name) => w!(this, "{}", name.display(self.db.upcast(), edition)),
|
||||
None => w!(this, "_anon_{}", id.into_raw()),
|
||||
},
|
||||
}
|
||||
w!(this, ": ");
|
||||
this.print_type_bounds(std::slice::from_ref(bound));
|
||||
this.print_type_bounds(std::slice::from_ref(bound), ¶ms.types_map);
|
||||
}
|
||||
});
|
||||
true
|
||||
|
|
|
|||
|
|
@ -1531,11 +1531,3 @@ fn macro_call_as_call_id_with_eager(
|
|||
pub struct UnresolvedMacro {
|
||||
pub path: hir_expand::mod_path::ModPath,
|
||||
}
|
||||
|
||||
intern::impl_internable!(
|
||||
crate::type_ref::TypeRef,
|
||||
crate::type_ref::TraitRef,
|
||||
crate::type_ref::TypeBound,
|
||||
crate::path::GenericArgs,
|
||||
generics::GenericParams,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -5,43 +5,53 @@ use hir_expand::{
|
|||
span_map::{SpanMap, SpanMapRef},
|
||||
AstId, HirFileId, InFile,
|
||||
};
|
||||
use intern::Interned;
|
||||
use span::{AstIdMap, AstIdNode};
|
||||
use stdx::thin_vec::ThinVec;
|
||||
use syntax::ast;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{db::DefDatabase, path::Path, type_ref::TypeBound};
|
||||
use crate::{
|
||||
db::DefDatabase,
|
||||
path::Path,
|
||||
type_ref::{TypeBound, TypePtr, TypeRef, TypeRefId, TypesMap, TypesSourceMap},
|
||||
};
|
||||
|
||||
pub struct LowerCtx<'a> {
|
||||
pub db: &'a dyn DefDatabase,
|
||||
file_id: HirFileId,
|
||||
span_map: OnceCell<SpanMap>,
|
||||
ast_id_map: OnceCell<Arc<AstIdMap>>,
|
||||
impl_trait_bounds: RefCell<Vec<Vec<Interned<TypeBound>>>>,
|
||||
impl_trait_bounds: RefCell<Vec<ThinVec<TypeBound>>>,
|
||||
// Prevent nested impl traits like `impl Foo<impl Bar>`.
|
||||
outer_impl_trait: RefCell<bool>,
|
||||
types_map: RefCell<(&'a mut TypesMap, &'a mut TypesSourceMap)>,
|
||||
}
|
||||
|
||||
pub(crate) struct OuterImplTraitGuard<'a> {
|
||||
ctx: &'a LowerCtx<'a>,
|
||||
pub(crate) struct OuterImplTraitGuard<'a, 'b> {
|
||||
ctx: &'a LowerCtx<'b>,
|
||||
old: bool,
|
||||
}
|
||||
|
||||
impl<'a> OuterImplTraitGuard<'a> {
|
||||
fn new(ctx: &'a LowerCtx<'a>, impl_trait: bool) -> Self {
|
||||
impl<'a, 'b> OuterImplTraitGuard<'a, 'b> {
|
||||
fn new(ctx: &'a LowerCtx<'b>, impl_trait: bool) -> Self {
|
||||
let old = ctx.outer_impl_trait.replace(impl_trait);
|
||||
Self { ctx, old }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for OuterImplTraitGuard<'a> {
|
||||
impl Drop for OuterImplTraitGuard<'_, '_> {
|
||||
fn drop(&mut self) {
|
||||
self.ctx.outer_impl_trait.replace(self.old);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> LowerCtx<'a> {
|
||||
pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
|
||||
pub fn new(
|
||||
db: &'a dyn DefDatabase,
|
||||
file_id: HirFileId,
|
||||
types_map: &'a mut TypesMap,
|
||||
types_source_map: &'a mut TypesSourceMap,
|
||||
) -> Self {
|
||||
LowerCtx {
|
||||
db,
|
||||
file_id,
|
||||
|
|
@ -49,6 +59,7 @@ impl<'a> LowerCtx<'a> {
|
|||
ast_id_map: OnceCell::new(),
|
||||
impl_trait_bounds: RefCell::new(Vec::new()),
|
||||
outer_impl_trait: RefCell::default(),
|
||||
types_map: RefCell::new((types_map, types_source_map)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -56,6 +67,8 @@ impl<'a> LowerCtx<'a> {
|
|||
db: &'a dyn DefDatabase,
|
||||
file_id: HirFileId,
|
||||
span_map: OnceCell<SpanMap>,
|
||||
types_map: &'a mut TypesMap,
|
||||
types_source_map: &'a mut TypesSourceMap,
|
||||
) -> Self {
|
||||
LowerCtx {
|
||||
db,
|
||||
|
|
@ -64,6 +77,7 @@ impl<'a> LowerCtx<'a> {
|
|||
ast_id_map: OnceCell::new(),
|
||||
impl_trait_bounds: RefCell::new(Vec::new()),
|
||||
outer_impl_trait: RefCell::default(),
|
||||
types_map: RefCell::new((types_map, types_source_map)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -82,11 +96,11 @@ impl<'a> LowerCtx<'a> {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn update_impl_traits_bounds(&self, bounds: Vec<Interned<TypeBound>>) {
|
||||
pub fn update_impl_traits_bounds(&self, bounds: ThinVec<TypeBound>) {
|
||||
self.impl_trait_bounds.borrow_mut().push(bounds);
|
||||
}
|
||||
|
||||
pub fn take_impl_traits_bounds(&self) -> Vec<Vec<Interned<TypeBound>>> {
|
||||
pub fn take_impl_traits_bounds(&self) -> Vec<ThinVec<TypeBound>> {
|
||||
self.impl_trait_bounds.take()
|
||||
}
|
||||
|
||||
|
|
@ -94,7 +108,32 @@ impl<'a> LowerCtx<'a> {
|
|||
*self.outer_impl_trait.borrow()
|
||||
}
|
||||
|
||||
pub(crate) fn outer_impl_trait_scope(&'a self, impl_trait: bool) -> OuterImplTraitGuard<'a> {
|
||||
pub(crate) fn outer_impl_trait_scope<'b>(
|
||||
&'b self,
|
||||
impl_trait: bool,
|
||||
) -> OuterImplTraitGuard<'b, 'a> {
|
||||
OuterImplTraitGuard::new(self, impl_trait)
|
||||
}
|
||||
|
||||
pub(crate) fn alloc_type_ref(&self, type_ref: TypeRef, node: TypePtr) -> TypeRefId {
|
||||
let mut types_map = self.types_map.borrow_mut();
|
||||
let (types_map, types_source_map) = &mut *types_map;
|
||||
let id = types_map.types.alloc(type_ref);
|
||||
types_source_map.types_map_back.insert(id, InFile::new(self.file_id, node));
|
||||
id
|
||||
}
|
||||
|
||||
pub(crate) fn alloc_type_ref_desugared(&self, type_ref: TypeRef) -> TypeRefId {
|
||||
self.types_map.borrow_mut().0.types.alloc(type_ref)
|
||||
}
|
||||
|
||||
pub(crate) fn alloc_error_type(&self) -> TypeRefId {
|
||||
self.types_map.borrow_mut().0.types.alloc(TypeRef::Error)
|
||||
}
|
||||
|
||||
// FIXME: If we alloc while holding this, well... Bad Things will happen. Need to change this
|
||||
// to use proper mutability instead of interior mutability.
|
||||
pub(crate) fn types_map(&self) -> std::cell::Ref<'_, TypesMap> {
|
||||
std::cell::Ref::map(self.types_map.borrow(), |it| &*it.0)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
|
|||
|
||||
let mut expn_text = String::new();
|
||||
if let Some(err) = exp.err {
|
||||
format_to!(expn_text, "/* error: {} */", err.render_to_string(&db).0);
|
||||
format_to!(expn_text, "/* error: {} */", err.render_to_string(&db).message);
|
||||
}
|
||||
let (parse, token_map) = exp.value;
|
||||
if expect_errors {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ use crate::{
|
|||
item_scope::{ImportId, ImportOrExternCrate, ImportType, PerNsGlobImports},
|
||||
item_tree::{
|
||||
self, AttrOwner, FieldsShape, FileItemTreeId, ImportKind, ItemTree, ItemTreeId,
|
||||
ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId,
|
||||
ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind,
|
||||
},
|
||||
macro_call_as_call_id, macro_call_as_call_id_with_eager,
|
||||
nameres::{
|
||||
|
|
@ -985,12 +985,8 @@ impl DefCollector<'_> {
|
|||
for (name, res) in resolutions {
|
||||
match name {
|
||||
Some(name) => {
|
||||
changed |= self.push_res_and_update_glob_vis(
|
||||
module_id,
|
||||
name,
|
||||
res.with_visibility(vis),
|
||||
import,
|
||||
);
|
||||
changed |=
|
||||
self.push_res_and_update_glob_vis(module_id, name, *res, vis, import);
|
||||
}
|
||||
None => {
|
||||
let tr = match res.take_types() {
|
||||
|
|
@ -1043,10 +1039,11 @@ impl DefCollector<'_> {
|
|||
.collect::<Vec<_>>();
|
||||
|
||||
for (glob_importing_module, glob_import_vis, use_) in glob_imports {
|
||||
let vis = glob_import_vis.min(vis, &self.def_map).unwrap_or(glob_import_vis);
|
||||
self.update_recursive(
|
||||
glob_importing_module,
|
||||
resolutions,
|
||||
glob_import_vis,
|
||||
vis,
|
||||
Some(ImportType::Glob(use_)),
|
||||
depth + 1,
|
||||
);
|
||||
|
|
@ -1058,8 +1055,44 @@ impl DefCollector<'_> {
|
|||
module_id: LocalModuleId,
|
||||
name: &Name,
|
||||
mut defs: PerNs,
|
||||
vis: Visibility,
|
||||
def_import_type: Option<ImportType>,
|
||||
) -> bool {
|
||||
// `extern crate crate_name` things can be re-exported as `pub use crate_name`.
|
||||
// But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name`
|
||||
// or `pub use ::crate_name`.
|
||||
//
|
||||
// This has been historically allowed, but may be not allowed in future
|
||||
// https://github.com/rust-lang/rust/issues/127909
|
||||
if let Some((_, v, it)) = defs.types.as_mut() {
|
||||
let is_extern_crate_reimport_without_prefix = || {
|
||||
let Some(ImportOrExternCrate::ExternCrate(_)) = it else {
|
||||
return false;
|
||||
};
|
||||
let Some(ImportType::Import(id)) = def_import_type else {
|
||||
return false;
|
||||
};
|
||||
let use_id = id.import.lookup(self.db).id;
|
||||
let item_tree = use_id.item_tree(self.db);
|
||||
let use_kind = item_tree[use_id.value].use_tree.kind();
|
||||
let UseTreeKind::Single { path, .. } = use_kind else {
|
||||
return false;
|
||||
};
|
||||
path.segments().len() < 2
|
||||
};
|
||||
if is_extern_crate_reimport_without_prefix() {
|
||||
*v = vis;
|
||||
} else {
|
||||
*v = v.min(vis, &self.def_map).unwrap_or(vis);
|
||||
}
|
||||
}
|
||||
if let Some((_, v, _)) = defs.values.as_mut() {
|
||||
*v = v.min(vis, &self.def_map).unwrap_or(vis);
|
||||
}
|
||||
if let Some((_, v, _)) = defs.macros.as_mut() {
|
||||
*v = v.min(vis, &self.def_map).unwrap_or(vis);
|
||||
}
|
||||
|
||||
let mut changed = false;
|
||||
|
||||
if let Some(ImportType::Glob(_)) = def_import_type {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
//!
|
||||
//! `ReachedFixedPoint` signals about this.
|
||||
|
||||
use either::Either;
|
||||
use hir_expand::{name::Name, Lookup};
|
||||
use span::Edition;
|
||||
use triomphe::Arc;
|
||||
|
|
@ -150,17 +151,8 @@ impl DefMap {
|
|||
|
||||
let mut arc;
|
||||
let mut current_map = self;
|
||||
loop {
|
||||
let new = current_map.resolve_path_fp_with_macro_single(
|
||||
db,
|
||||
mode,
|
||||
original_module,
|
||||
path,
|
||||
shadow,
|
||||
expected_macro_subns,
|
||||
);
|
||||
|
||||
// Merge `new` into `result`.
|
||||
let mut merge = |new: ResolvePathResult| {
|
||||
result.resolved_def = result.resolved_def.or(new.resolved_def);
|
||||
if result.reached_fixedpoint == ReachedFixedPoint::No {
|
||||
result.reached_fixedpoint = new.reached_fixedpoint;
|
||||
|
|
@ -171,7 +163,9 @@ impl DefMap {
|
|||
(Some(old), Some(new)) => Some(old.max(new)),
|
||||
(None, new) => new,
|
||||
};
|
||||
};
|
||||
|
||||
loop {
|
||||
match current_map.block {
|
||||
Some(block) if original_module == Self::ROOT => {
|
||||
// Block modules "inherit" names from its parent module.
|
||||
|
|
@ -180,8 +174,38 @@ impl DefMap {
|
|||
current_map = &arc;
|
||||
}
|
||||
// Proper (non-block) modules, including those in block `DefMap`s, don't.
|
||||
_ => return result,
|
||||
_ => {
|
||||
if original_module != Self::ROOT && current_map.block.is_some() {
|
||||
// A module inside a block. Do not resolve items declared in upper blocks, but we do need to get
|
||||
// the prelude items (which are not inserted into blocks because they can be overridden there).
|
||||
original_module = Self::ROOT;
|
||||
arc = db.crate_def_map(self.krate);
|
||||
current_map = &arc;
|
||||
|
||||
let new = current_map.resolve_path_fp_in_all_preludes(
|
||||
db,
|
||||
mode,
|
||||
original_module,
|
||||
path,
|
||||
shadow,
|
||||
);
|
||||
merge(new);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
let new = current_map.resolve_path_fp_with_macro_single(
|
||||
db,
|
||||
mode,
|
||||
original_module,
|
||||
path,
|
||||
shadow,
|
||||
expected_macro_subns,
|
||||
);
|
||||
|
||||
merge(new);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -195,7 +219,7 @@ impl DefMap {
|
|||
expected_macro_subns: Option<MacroSubNs>,
|
||||
) -> ResolvePathResult {
|
||||
let mut segments = path.segments().iter().enumerate();
|
||||
let mut curr_per_ns = match path.kind {
|
||||
let curr_per_ns = match path.kind {
|
||||
PathKind::DollarCrate(krate) => {
|
||||
if krate == self.krate {
|
||||
cov_mark::hit!(macro_dollar_crate_self);
|
||||
|
|
@ -296,25 +320,96 @@ impl DefMap {
|
|||
|
||||
PerNs::types(module.into(), Visibility::Public, None)
|
||||
}
|
||||
PathKind::Abs => {
|
||||
// 2018-style absolute path -- only extern prelude
|
||||
let segment = match segments.next() {
|
||||
Some((_, segment)) => segment,
|
||||
PathKind::Abs => match self.resolve_path_abs(&mut segments, path) {
|
||||
Either::Left(it) => it,
|
||||
Either::Right(reached_fixed_point) => {
|
||||
return ResolvePathResult::empty(reached_fixed_point)
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
self.resolve_remaining_segments(segments, curr_per_ns, path, db, shadow, original_module)
|
||||
}
|
||||
|
||||
/// Resolves a path only in the preludes, without accounting for item scopes.
|
||||
pub(super) fn resolve_path_fp_in_all_preludes(
|
||||
&self,
|
||||
db: &dyn DefDatabase,
|
||||
mode: ResolveMode,
|
||||
original_module: LocalModuleId,
|
||||
path: &ModPath,
|
||||
shadow: BuiltinShadowMode,
|
||||
) -> ResolvePathResult {
|
||||
let mut segments = path.segments().iter().enumerate();
|
||||
let curr_per_ns = match path.kind {
|
||||
// plain import or absolute path in 2015: crate-relative with
|
||||
// fallback to extern prelude (with the simplification in
|
||||
// rust-lang/rust#57745)
|
||||
// FIXME there must be a nicer way to write this condition
|
||||
PathKind::Plain | PathKind::Abs
|
||||
if self.data.edition == Edition::Edition2015
|
||||
&& (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
|
||||
{
|
||||
let (_, segment) = match segments.next() {
|
||||
Some((idx, segment)) => (idx, segment),
|
||||
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
|
||||
};
|
||||
if let Some(&(def, extern_crate)) = self.data.extern_prelude.get(segment) {
|
||||
tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
|
||||
PerNs::types(
|
||||
def.into(),
|
||||
Visibility::Public,
|
||||
extern_crate.map(ImportOrExternCrate::ExternCrate),
|
||||
)
|
||||
} else {
|
||||
return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
|
||||
tracing::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
|
||||
self.resolve_name_in_extern_prelude(segment)
|
||||
}
|
||||
PathKind::Plain => {
|
||||
let (_, segment) = match segments.next() {
|
||||
Some((idx, segment)) => (idx, segment),
|
||||
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
|
||||
};
|
||||
tracing::debug!("resolving {:?} in module", segment);
|
||||
self.resolve_name_in_all_preludes(db, segment)
|
||||
}
|
||||
PathKind::Abs => match self.resolve_path_abs(&mut segments, path) {
|
||||
Either::Left(it) => it,
|
||||
Either::Right(reached_fixed_point) => {
|
||||
return ResolvePathResult::empty(reached_fixed_point)
|
||||
}
|
||||
},
|
||||
PathKind::DollarCrate(_) | PathKind::Crate | PathKind::Super(_) => {
|
||||
return ResolvePathResult::empty(ReachedFixedPoint::Yes)
|
||||
}
|
||||
};
|
||||
|
||||
self.resolve_remaining_segments(segments, curr_per_ns, path, db, shadow, original_module)
|
||||
}
|
||||
|
||||
/// 2018-style absolute path -- only extern prelude
|
||||
fn resolve_path_abs<'a>(
|
||||
&self,
|
||||
segments: &mut impl Iterator<Item = (usize, &'a Name)>,
|
||||
path: &ModPath,
|
||||
) -> Either<PerNs, ReachedFixedPoint> {
|
||||
let segment = match segments.next() {
|
||||
Some((_, segment)) => segment,
|
||||
None => return Either::Right(ReachedFixedPoint::Yes),
|
||||
};
|
||||
if let Some(&(def, extern_crate)) = self.data.extern_prelude.get(segment) {
|
||||
tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
|
||||
Either::Left(PerNs::types(
|
||||
def.into(),
|
||||
Visibility::Public,
|
||||
extern_crate.map(ImportOrExternCrate::ExternCrate),
|
||||
))
|
||||
} else {
|
||||
Either::Right(ReachedFixedPoint::No) // extern crate declarations can add to the extern prelude
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_remaining_segments<'a>(
|
||||
&self,
|
||||
segments: impl Iterator<Item = (usize, &'a Name)>,
|
||||
mut curr_per_ns: PerNs,
|
||||
path: &ModPath,
|
||||
db: &dyn DefDatabase,
|
||||
shadow: BuiltinShadowMode,
|
||||
original_module: LocalModuleId,
|
||||
) -> ResolvePathResult {
|
||||
for (i, segment) in segments {
|
||||
let (curr, vis, imp) = match curr_per_ns.take_types_full() {
|
||||
Some(r) => r,
|
||||
|
|
@ -475,24 +570,9 @@ impl DefMap {
|
|||
// they might been shadowed by local names.
|
||||
return PerNs::none();
|
||||
}
|
||||
self.data.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| {
|
||||
PerNs::types(
|
||||
it.into(),
|
||||
Visibility::Public,
|
||||
extern_crate.map(ImportOrExternCrate::ExternCrate),
|
||||
)
|
||||
})
|
||||
};
|
||||
let macro_use_prelude = || {
|
||||
self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| {
|
||||
PerNs::macros(
|
||||
it,
|
||||
Visibility::Public,
|
||||
// FIXME?
|
||||
None, // extern_crate.map(ImportOrExternCrate::ExternCrate),
|
||||
)
|
||||
})
|
||||
self.resolve_name_in_extern_prelude(name)
|
||||
};
|
||||
let macro_use_prelude = || self.resolve_in_macro_use_prelude(name);
|
||||
let prelude = || {
|
||||
if self.block.is_some() && module == DefMap::ROOT {
|
||||
return PerNs::none();
|
||||
|
|
@ -507,6 +587,38 @@ impl DefMap {
|
|||
.or_else(prelude)
|
||||
}
|
||||
|
||||
fn resolve_name_in_all_preludes(&self, db: &dyn DefDatabase, name: &Name) -> PerNs {
|
||||
// Resolve in:
|
||||
// - extern prelude / macro_use prelude
|
||||
// - std prelude
|
||||
let extern_prelude = self.resolve_name_in_extern_prelude(name);
|
||||
let macro_use_prelude = || self.resolve_in_macro_use_prelude(name);
|
||||
let prelude = || self.resolve_in_prelude(db, name);
|
||||
|
||||
extern_prelude.or_else(macro_use_prelude).or_else(prelude)
|
||||
}
|
||||
|
||||
fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
|
||||
self.data.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| {
|
||||
PerNs::types(
|
||||
it.into(),
|
||||
Visibility::Public,
|
||||
extern_crate.map(ImportOrExternCrate::ExternCrate),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn resolve_in_macro_use_prelude(&self, name: &Name) -> PerNs {
|
||||
self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| {
|
||||
PerNs::macros(
|
||||
it,
|
||||
Visibility::Public,
|
||||
// FIXME?
|
||||
None, // extern_crate.map(ImportOrExternCrate::ExternCrate),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn resolve_name_in_crate_root_or_extern_prelude(
|
||||
&self,
|
||||
db: &dyn DefDatabase,
|
||||
|
|
@ -525,16 +637,7 @@ impl DefMap {
|
|||
// Don't resolve extern prelude in pseudo-module of a block.
|
||||
return PerNs::none();
|
||||
}
|
||||
self.data.extern_prelude.get(name).copied().map_or(
|
||||
PerNs::none(),
|
||||
|(it, extern_crate)| {
|
||||
PerNs::types(
|
||||
it.into(),
|
||||
Visibility::Public,
|
||||
extern_crate.map(ImportOrExternCrate::ExternCrate),
|
||||
)
|
||||
},
|
||||
)
|
||||
self.resolve_name_in_extern_prelude(name)
|
||||
};
|
||||
|
||||
from_crate_root.or_else(from_extern_prelude)
|
||||
|
|
|
|||
|
|
@ -385,6 +385,52 @@ pub struct Arc;
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extern_crate_reexport() {
|
||||
check(
|
||||
r#"
|
||||
//- /main.rs crate:main deps:importer
|
||||
use importer::*;
|
||||
use importer::extern_crate1::exported::*;
|
||||
use importer::allowed_reexport::*;
|
||||
use importer::extern_crate2::*;
|
||||
use importer::not_allowed_reexport1;
|
||||
use importer::not_allowed_reexport2;
|
||||
|
||||
//- /importer.rs crate:importer deps:extern_crate1,extern_crate2
|
||||
extern crate extern_crate1;
|
||||
extern crate extern_crate2;
|
||||
|
||||
pub use extern_crate1;
|
||||
pub use extern_crate1 as allowed_reexport;
|
||||
|
||||
pub use ::extern_crate;
|
||||
pub use self::extern_crate as not_allowed_reexport1;
|
||||
pub use crate::extern_crate as not_allowed_reexport2;
|
||||
|
||||
//- /extern_crate1.rs crate:extern_crate1
|
||||
pub mod exported {
|
||||
pub struct PublicItem;
|
||||
struct PrivateItem;
|
||||
}
|
||||
|
||||
pub struct Exported;
|
||||
|
||||
//- /extern_crate2.rs crate:extern_crate2
|
||||
pub struct NotExported;
|
||||
"#,
|
||||
expect![[r#"
|
||||
crate
|
||||
Exported: t v
|
||||
PublicItem: t v
|
||||
allowed_reexport: t
|
||||
exported: t
|
||||
not_allowed_reexport1: _
|
||||
not_allowed_reexport2: _
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extern_crate_rename_2015_edition() {
|
||||
check(
|
||||
|
|
|
|||
|
|
@ -412,3 +412,42 @@ use reexport::*;
|
|||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn regression_18308() {
|
||||
check(
|
||||
r#"
|
||||
use outer::*;
|
||||
|
||||
mod outer {
|
||||
mod inner_superglob {
|
||||
pub use super::*;
|
||||
}
|
||||
|
||||
// The importing order matters!
|
||||
pub use inner_superglob::*;
|
||||
use super::glob_target::*;
|
||||
}
|
||||
|
||||
mod glob_target {
|
||||
pub struct ShouldBePrivate;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
crate
|
||||
glob_target: t
|
||||
outer: t
|
||||
|
||||
crate::glob_target
|
||||
ShouldBePrivate: t v
|
||||
|
||||
crate::outer
|
||||
ShouldBePrivate: t v
|
||||
inner_superglob: t
|
||||
|
||||
crate::outer::inner_superglob
|
||||
ShouldBePrivate: t v
|
||||
inner_superglob: t
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -253,7 +253,8 @@ m!(Z);
|
|||
let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
|
||||
assert_eq!(module_data.scope.resolutions().count(), 4);
|
||||
});
|
||||
let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
|
||||
let n_recalculated_item_trees =
|
||||
events.iter().filter(|it| it.contains("item_tree(")).count();
|
||||
assert_eq!(n_recalculated_item_trees, 6);
|
||||
let n_reparsed_macros =
|
||||
events.iter().filter(|it| it.contains("parse_macro_expansion(")).count();
|
||||
|
|
@ -308,7 +309,7 @@ pub type Ty = ();
|
|||
let events = db.log_executed(|| {
|
||||
db.file_item_tree(pos.file_id.into());
|
||||
});
|
||||
let n_calculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
|
||||
let n_calculated_item_trees = events.iter().filter(|it| it.contains("item_tree(")).count();
|
||||
assert_eq!(n_calculated_item_trees, 1);
|
||||
let n_parsed_files = events.iter().filter(|it| it.contains("parse(")).count();
|
||||
assert_eq!(n_parsed_files, 1);
|
||||
|
|
|
|||
|
|
@ -9,11 +9,12 @@ use std::{
|
|||
use crate::{
|
||||
lang_item::LangItemTarget,
|
||||
lower::LowerCtx,
|
||||
type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
|
||||
type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRefId},
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
use intern::Interned;
|
||||
use span::Edition;
|
||||
use stdx::thin_vec::thin_vec_with_header_struct;
|
||||
use syntax::ast;
|
||||
|
||||
pub use hir_expand::mod_path::{path, ModPath, PathKind};
|
||||
|
|
@ -47,20 +48,33 @@ impl Display for ImportAliasDisplay<'_> {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Path {
|
||||
/// A normal path
|
||||
Normal {
|
||||
/// Type based path like `<T>::foo`.
|
||||
/// Note that paths like `<Type as Trait>::foo` are desugared to `Trait::<Self=Type>::foo`.
|
||||
type_anchor: Option<Interned<TypeRef>>,
|
||||
mod_path: Interned<ModPath>,
|
||||
/// Invariant: the same len as `self.mod_path.segments` or `None` if all segments are `None`.
|
||||
generic_args: Option<Box<[Option<Interned<GenericArgs>>]>>,
|
||||
},
|
||||
/// `BarePath` is used when the path has neither generics nor type anchor, since the vast majority of paths
|
||||
/// are in this category, and splitting `Path` this way allows it to be more thin. When the path has either generics
|
||||
/// or type anchor, it is `Path::Normal` with the generics filled with `None` even if there are none (practically
|
||||
/// this is not a problem since many more paths have generics than a type anchor).
|
||||
BarePath(Interned<ModPath>),
|
||||
/// `Path::Normal` may have empty generics and type anchor (but generic args will be filled with `None`).
|
||||
Normal(NormalPath),
|
||||
/// A link to a lang item. It is used in desugaring of things like `it?`. We can show these
|
||||
/// links via a normal path since they might be private and not accessible in the usage place.
|
||||
LangItem(LangItemTarget, Option<Name>),
|
||||
}
|
||||
|
||||
// This type is being used a lot, make sure it doesn't grow unintentionally.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
const _: () = {
|
||||
assert!(size_of::<Path>() == 16);
|
||||
assert!(size_of::<Option<Path>>() == 16);
|
||||
};
|
||||
|
||||
thin_vec_with_header_struct! {
|
||||
pub new(pub(crate)) struct NormalPath, NormalPathHeader {
|
||||
pub generic_args: [Option<GenericArgs>],
|
||||
pub type_anchor: Option<TypeRefId>,
|
||||
pub mod_path: Interned<ModPath>; ref,
|
||||
}
|
||||
}
|
||||
|
||||
/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
|
||||
/// also includes bindings of associated types, like in `Iterator<Item = Foo>`.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
|
@ -86,20 +100,20 @@ pub struct AssociatedTypeBinding {
|
|||
pub name: Name,
|
||||
/// The generic arguments to the associated type. e.g. For `Trait<Assoc<'a, T> = &'a T>`, this
|
||||
/// would be `['a, T]`.
|
||||
pub args: Option<Interned<GenericArgs>>,
|
||||
pub args: Option<GenericArgs>,
|
||||
/// The type bound to this associated type (in `Item = T`, this would be the
|
||||
/// `T`). This can be `None` if there are bounds instead.
|
||||
pub type_ref: Option<TypeRef>,
|
||||
pub type_ref: Option<TypeRefId>,
|
||||
/// Bounds for the associated type, like in `Iterator<Item:
|
||||
/// SomeOtherTrait>`. (This is the unstable `associated_type_bounds`
|
||||
/// feature.)
|
||||
pub bounds: Box<[Interned<TypeBound>]>,
|
||||
pub bounds: Box<[TypeBound]>,
|
||||
}
|
||||
|
||||
/// A single generic argument.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum GenericArg {
|
||||
Type(TypeRef),
|
||||
Type(TypeRefId),
|
||||
Lifetime(LifetimeRef),
|
||||
Const(ConstRef),
|
||||
}
|
||||
|
|
@ -112,50 +126,49 @@ impl Path {
|
|||
}
|
||||
|
||||
/// Converts a known mod path to `Path`.
|
||||
pub fn from_known_path(
|
||||
path: ModPath,
|
||||
generic_args: impl Into<Box<[Option<Interned<GenericArgs>>]>>,
|
||||
) -> Path {
|
||||
let generic_args = generic_args.into();
|
||||
assert_eq!(path.len(), generic_args.len());
|
||||
Path::Normal {
|
||||
type_anchor: None,
|
||||
mod_path: Interned::new(path),
|
||||
generic_args: Some(generic_args),
|
||||
}
|
||||
pub fn from_known_path(path: ModPath, generic_args: Vec<Option<GenericArgs>>) -> Path {
|
||||
Path::Normal(NormalPath::new(None, Interned::new(path), generic_args))
|
||||
}
|
||||
|
||||
/// Converts a known mod path to `Path`.
|
||||
pub fn from_known_path_with_no_generic(path: ModPath) -> Path {
|
||||
Path::Normal { type_anchor: None, mod_path: Interned::new(path), generic_args: None }
|
||||
Path::BarePath(Interned::new(path))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn kind(&self) -> &PathKind {
|
||||
match self {
|
||||
Path::Normal { mod_path, .. } => &mod_path.kind,
|
||||
Path::BarePath(mod_path) => &mod_path.kind,
|
||||
Path::Normal(path) => &path.mod_path().kind,
|
||||
Path::LangItem(..) => &PathKind::Abs,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_anchor(&self) -> Option<&TypeRef> {
|
||||
#[inline]
|
||||
pub fn type_anchor(&self) -> Option<TypeRefId> {
|
||||
match self {
|
||||
Path::Normal { type_anchor, .. } => type_anchor.as_deref(),
|
||||
Path::LangItem(..) => None,
|
||||
Path::Normal(path) => path.type_anchor(),
|
||||
Path::LangItem(..) | Path::BarePath(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn generic_args(&self) -> Option<&[Option<GenericArgs>]> {
|
||||
match self {
|
||||
Path::Normal(path) => Some(path.generic_args()),
|
||||
Path::LangItem(..) | Path::BarePath(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn segments(&self) -> PathSegments<'_> {
|
||||
match self {
|
||||
Path::Normal { mod_path, generic_args, .. } => {
|
||||
let s = PathSegments {
|
||||
segments: mod_path.segments(),
|
||||
generic_args: generic_args.as_deref(),
|
||||
};
|
||||
if let Some(generic_args) = s.generic_args {
|
||||
assert_eq!(s.segments.len(), generic_args.len());
|
||||
}
|
||||
s
|
||||
Path::BarePath(mod_path) => {
|
||||
PathSegments { segments: mod_path.segments(), generic_args: None }
|
||||
}
|
||||
Path::Normal(path) => PathSegments {
|
||||
segments: path.mod_path().segments(),
|
||||
generic_args: Some(path.generic_args()),
|
||||
},
|
||||
Path::LangItem(_, seg) => PathSegments {
|
||||
segments: seg.as_ref().map_or(&[], |seg| std::slice::from_ref(seg)),
|
||||
generic_args: None,
|
||||
|
|
@ -165,34 +178,55 @@ impl Path {
|
|||
|
||||
pub fn mod_path(&self) -> Option<&ModPath> {
|
||||
match self {
|
||||
Path::Normal { mod_path, .. } => Some(mod_path),
|
||||
Path::BarePath(mod_path) => Some(mod_path),
|
||||
Path::Normal(path) => Some(path.mod_path()),
|
||||
Path::LangItem(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn qualifier(&self) -> Option<Path> {
|
||||
let Path::Normal { mod_path, generic_args, type_anchor } = self else {
|
||||
return None;
|
||||
};
|
||||
if mod_path.is_ident() {
|
||||
return None;
|
||||
match self {
|
||||
Path::BarePath(mod_path) => {
|
||||
if mod_path.is_ident() {
|
||||
return None;
|
||||
}
|
||||
Some(Path::BarePath(Interned::new(ModPath::from_segments(
|
||||
mod_path.kind,
|
||||
mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
|
||||
))))
|
||||
}
|
||||
Path::Normal(path) => {
|
||||
let mod_path = path.mod_path();
|
||||
if mod_path.is_ident() {
|
||||
return None;
|
||||
}
|
||||
let type_anchor = path.type_anchor();
|
||||
let generic_args = path.generic_args();
|
||||
let qualifier_mod_path = Interned::new(ModPath::from_segments(
|
||||
mod_path.kind,
|
||||
mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
|
||||
));
|
||||
let qualifier_generic_args = &generic_args[..generic_args.len() - 1];
|
||||
Some(Path::Normal(NormalPath::new(
|
||||
type_anchor,
|
||||
qualifier_mod_path,
|
||||
qualifier_generic_args.iter().cloned(),
|
||||
)))
|
||||
}
|
||||
Path::LangItem(..) => None,
|
||||
}
|
||||
let res = Path::Normal {
|
||||
type_anchor: type_anchor.clone(),
|
||||
mod_path: Interned::new(ModPath::from_segments(
|
||||
mod_path.kind,
|
||||
mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
|
||||
)),
|
||||
generic_args: generic_args.as_ref().map(|it| it[..it.len() - 1].to_vec().into()),
|
||||
};
|
||||
Some(res)
|
||||
}
|
||||
|
||||
pub fn is_self_type(&self) -> bool {
|
||||
let Path::Normal { mod_path, generic_args, type_anchor } = self else {
|
||||
return false;
|
||||
};
|
||||
type_anchor.is_none() && generic_args.as_deref().is_none() && mod_path.is_Self()
|
||||
match self {
|
||||
Path::BarePath(mod_path) => mod_path.is_Self(),
|
||||
Path::Normal(path) => {
|
||||
path.type_anchor().is_none()
|
||||
&& path.mod_path().is_Self()
|
||||
&& path.generic_args().iter().all(|args| args.is_none())
|
||||
}
|
||||
Path::LangItem(..) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -204,7 +238,7 @@ pub struct PathSegment<'a> {
|
|||
|
||||
pub struct PathSegments<'a> {
|
||||
segments: &'a [Name],
|
||||
generic_args: Option<&'a [Option<Interned<GenericArgs>>]>,
|
||||
generic_args: Option<&'a [Option<GenericArgs>]>,
|
||||
}
|
||||
|
||||
impl<'a> PathSegments<'a> {
|
||||
|
|
@ -224,7 +258,7 @@ impl<'a> PathSegments<'a> {
|
|||
pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
|
||||
let res = PathSegment {
|
||||
name: self.segments.get(idx)?,
|
||||
args_and_bindings: self.generic_args.and_then(|it| it.get(idx)?.as_deref()),
|
||||
args_and_bindings: self.generic_args.and_then(|it| it.get(idx)?.as_ref()),
|
||||
};
|
||||
Some(res)
|
||||
}
|
||||
|
|
@ -244,7 +278,7 @@ impl<'a> PathSegments<'a> {
|
|||
self.segments
|
||||
.iter()
|
||||
.zip(self.generic_args.into_iter().flatten().chain(iter::repeat(&None)))
|
||||
.map(|(name, args)| PathSegment { name, args_and_bindings: args.as_deref() })
|
||||
.map(|(name, args)| PathSegment { name, args_and_bindings: args.as_ref() })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -268,16 +302,6 @@ impl GenericArgs {
|
|||
|
||||
impl From<Name> for Path {
|
||||
fn from(name: Name) -> Path {
|
||||
Path::Normal {
|
||||
type_anchor: None,
|
||||
mod_path: Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))),
|
||||
generic_args: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Name> for Box<Path> {
|
||||
fn from(name: Name) -> Box<Path> {
|
||||
Box::new(Path::from(name))
|
||||
Path::BarePath(Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@
|
|||
|
||||
use std::iter;
|
||||
|
||||
use crate::{lower::LowerCtx, type_ref::ConstRef};
|
||||
use crate::{lower::LowerCtx, path::NormalPath, type_ref::ConstRef};
|
||||
|
||||
use hir_expand::{
|
||||
mod_path::resolve_crate_root,
|
||||
name::{AsName, Name},
|
||||
};
|
||||
use intern::{sym, Interned};
|
||||
use stdx::thin_vec::EmptyOptimizedThinVec;
|
||||
use syntax::ast::{self, AstNode, HasGenericArgs, HasTypeBounds};
|
||||
|
||||
use crate::{
|
||||
|
|
@ -51,8 +52,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
|
|||
segment.param_list(),
|
||||
segment.ret_type(),
|
||||
)
|
||||
})
|
||||
.map(Interned::new);
|
||||
});
|
||||
if args.is_some() {
|
||||
generic_args.resize(segments.len(), None);
|
||||
generic_args.push(args);
|
||||
|
|
@ -70,16 +70,14 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
|
|||
match trait_ref {
|
||||
// <T>::foo
|
||||
None => {
|
||||
type_anchor = Some(Interned::new(self_type));
|
||||
type_anchor = Some(self_type);
|
||||
kind = PathKind::Plain;
|
||||
}
|
||||
// <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
|
||||
Some(trait_ref) => {
|
||||
let Path::Normal { mod_path, generic_args: path_generic_args, .. } =
|
||||
Path::from_src(ctx, trait_ref.path()?)?
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
let path = Path::from_src(ctx, trait_ref.path()?)?;
|
||||
let mod_path = path.mod_path()?;
|
||||
let path_generic_args = path.generic_args();
|
||||
let num_segments = mod_path.segments().len();
|
||||
kind = mod_path.kind;
|
||||
|
||||
|
|
@ -95,7 +93,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
|
|||
|
||||
// Insert the type reference (T in the above example) as Self parameter for the trait
|
||||
let last_segment = generic_args.get_mut(segments.len() - num_segments)?;
|
||||
*last_segment = Some(Interned::new(match last_segment.take() {
|
||||
*last_segment = Some(match last_segment.take() {
|
||||
Some(it) => GenericArgs {
|
||||
args: iter::once(self_type)
|
||||
.chain(it.args.iter().cloned())
|
||||
|
|
@ -110,7 +108,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
|
|||
has_self_type: true,
|
||||
..GenericArgs::empty()
|
||||
},
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -137,7 +135,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
|
|||
};
|
||||
}
|
||||
segments.reverse();
|
||||
if !generic_args.is_empty() {
|
||||
if !generic_args.is_empty() || type_anchor.is_some() {
|
||||
generic_args.resize(segments.len(), None);
|
||||
generic_args.reverse();
|
||||
}
|
||||
|
|
@ -166,11 +164,11 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
|
|||
}
|
||||
|
||||
let mod_path = Interned::new(ModPath::from_segments(kind, segments));
|
||||
return Some(Path::Normal {
|
||||
type_anchor,
|
||||
mod_path,
|
||||
generic_args: if generic_args.is_empty() { None } else { Some(generic_args.into()) },
|
||||
});
|
||||
if type_anchor.is_none() && generic_args.is_empty() {
|
||||
return Some(Path::BarePath(mod_path));
|
||||
} else {
|
||||
return Some(Path::Normal(NormalPath::new(type_anchor, mod_path, generic_args)));
|
||||
}
|
||||
|
||||
fn qualifier(path: &ast::Path) -> Option<ast::Path> {
|
||||
if let Some(q) = path.qualifier() {
|
||||
|
|
@ -194,11 +192,13 @@ pub(super) fn lower_generic_args(
|
|||
match generic_arg {
|
||||
ast::GenericArg::TypeArg(type_arg) => {
|
||||
let type_ref = TypeRef::from_ast_opt(lower_ctx, type_arg.ty());
|
||||
type_ref.walk(&mut |tr| {
|
||||
let types_map = lower_ctx.types_map();
|
||||
TypeRef::walk(type_ref, &types_map, &mut |tr| {
|
||||
if let TypeRef::ImplTrait(bounds) = tr {
|
||||
lower_ctx.update_impl_traits_bounds(bounds.clone());
|
||||
}
|
||||
});
|
||||
drop(types_map);
|
||||
args.push(GenericArg::Type(type_ref));
|
||||
}
|
||||
ast::GenericArg::AssocTypeArg(assoc_type_arg) => {
|
||||
|
|
@ -212,20 +212,19 @@ pub(super) fn lower_generic_args(
|
|||
let name = name_ref.as_name();
|
||||
let args = assoc_type_arg
|
||||
.generic_arg_list()
|
||||
.and_then(|args| lower_generic_args(lower_ctx, args))
|
||||
.map(Interned::new);
|
||||
.and_then(|args| lower_generic_args(lower_ctx, args));
|
||||
let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
|
||||
let type_ref = type_ref.inspect(|tr| {
|
||||
tr.walk(&mut |tr| {
|
||||
let type_ref = type_ref.inspect(|&tr| {
|
||||
let types_map = lower_ctx.types_map();
|
||||
TypeRef::walk(tr, &types_map, &mut |tr| {
|
||||
if let TypeRef::ImplTrait(bounds) = tr {
|
||||
lower_ctx.update_impl_traits_bounds(bounds.clone());
|
||||
}
|
||||
});
|
||||
drop(types_map);
|
||||
});
|
||||
let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
|
||||
l.bounds()
|
||||
.map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it)))
|
||||
.collect()
|
||||
l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect()
|
||||
} else {
|
||||
Box::default()
|
||||
};
|
||||
|
|
@ -269,7 +268,9 @@ fn lower_generic_args_from_fn_path(
|
|||
let type_ref = TypeRef::from_ast_opt(ctx, param.ty());
|
||||
param_types.push(type_ref);
|
||||
}
|
||||
let args = Box::new([GenericArg::Type(TypeRef::Tuple(param_types))]);
|
||||
let args = Box::new([GenericArg::Type(
|
||||
ctx.alloc_type_ref_desugared(TypeRef::Tuple(EmptyOptimizedThinVec::from_iter(param_types))),
|
||||
)]);
|
||||
let bindings = if let Some(ret_type) = ret_type {
|
||||
let type_ref = TypeRef::from_ast_opt(ctx, ret_type.ty());
|
||||
Box::new([AssociatedTypeBinding {
|
||||
|
|
@ -280,7 +281,7 @@ fn lower_generic_args_from_fn_path(
|
|||
}])
|
||||
} else {
|
||||
// -> ()
|
||||
let type_ref = TypeRef::Tuple(Vec::new());
|
||||
let type_ref = ctx.alloc_type_ref_desugared(TypeRef::unit());
|
||||
Box::new([AssociatedTypeBinding {
|
||||
name: Name::new_symbol_root(sym::Output.clone()),
|
||||
args: None,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
//! Display and pretty printing routines.
|
||||
|
||||
use std::fmt::{self, Write};
|
||||
use std::{
|
||||
fmt::{self, Write},
|
||||
mem,
|
||||
};
|
||||
|
||||
use hir_expand::mod_path::PathKind;
|
||||
use intern::Interned;
|
||||
use itertools::Itertools;
|
||||
use span::Edition;
|
||||
|
||||
|
|
@ -11,12 +13,15 @@ use crate::{
|
|||
db::DefDatabase,
|
||||
lang_item::LangItemTarget,
|
||||
path::{GenericArg, GenericArgs, Path},
|
||||
type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef},
|
||||
type_ref::{
|
||||
Mutability, TraitBoundModifier, TypeBound, TypeRef, TypeRefId, TypesMap, UseArgRef,
|
||||
},
|
||||
};
|
||||
|
||||
pub(crate) fn print_path(
|
||||
db: &dyn DefDatabase,
|
||||
path: &Path,
|
||||
map: &TypesMap,
|
||||
buf: &mut dyn Write,
|
||||
edition: Edition,
|
||||
) -> fmt::Result {
|
||||
|
|
@ -58,7 +63,7 @@ pub(crate) fn print_path(
|
|||
match path.type_anchor() {
|
||||
Some(anchor) => {
|
||||
write!(buf, "<")?;
|
||||
print_type_ref(db, anchor, buf, edition)?;
|
||||
print_type_ref(db, anchor, map, buf, edition)?;
|
||||
write!(buf, ">::")?;
|
||||
}
|
||||
None => match path.kind() {
|
||||
|
|
@ -87,7 +92,7 @@ pub(crate) fn print_path(
|
|||
write!(buf, "{}", segment.name.display(db.upcast(), edition))?;
|
||||
if let Some(generics) = segment.args_and_bindings {
|
||||
write!(buf, "::<")?;
|
||||
print_generic_args(db, generics, buf, edition)?;
|
||||
print_generic_args(db, generics, map, buf, edition)?;
|
||||
|
||||
write!(buf, ">")?;
|
||||
}
|
||||
|
|
@ -99,6 +104,7 @@ pub(crate) fn print_path(
|
|||
pub(crate) fn print_generic_args(
|
||||
db: &dyn DefDatabase,
|
||||
generics: &GenericArgs,
|
||||
map: &TypesMap,
|
||||
buf: &mut dyn Write,
|
||||
edition: Edition,
|
||||
) -> fmt::Result {
|
||||
|
|
@ -106,7 +112,7 @@ pub(crate) fn print_generic_args(
|
|||
let args = if generics.has_self_type {
|
||||
let (self_ty, args) = generics.args.split_first().unwrap();
|
||||
write!(buf, "Self=")?;
|
||||
print_generic_arg(db, self_ty, buf, edition)?;
|
||||
print_generic_arg(db, self_ty, map, buf, edition)?;
|
||||
first = false;
|
||||
args
|
||||
} else {
|
||||
|
|
@ -117,7 +123,7 @@ pub(crate) fn print_generic_args(
|
|||
write!(buf, ", ")?;
|
||||
}
|
||||
first = false;
|
||||
print_generic_arg(db, arg, buf, edition)?;
|
||||
print_generic_arg(db, arg, map, buf, edition)?;
|
||||
}
|
||||
for binding in generics.bindings.iter() {
|
||||
if !first {
|
||||
|
|
@ -127,11 +133,11 @@ pub(crate) fn print_generic_args(
|
|||
write!(buf, "{}", binding.name.display(db.upcast(), edition))?;
|
||||
if !binding.bounds.is_empty() {
|
||||
write!(buf, ": ")?;
|
||||
print_type_bounds(db, &binding.bounds, buf, edition)?;
|
||||
print_type_bounds(db, &binding.bounds, map, buf, edition)?;
|
||||
}
|
||||
if let Some(ty) = &binding.type_ref {
|
||||
if let Some(ty) = binding.type_ref {
|
||||
write!(buf, " = ")?;
|
||||
print_type_ref(db, ty, buf, edition)?;
|
||||
print_type_ref(db, ty, map, buf, edition)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
@ -140,11 +146,12 @@ pub(crate) fn print_generic_args(
|
|||
pub(crate) fn print_generic_arg(
|
||||
db: &dyn DefDatabase,
|
||||
arg: &GenericArg,
|
||||
map: &TypesMap,
|
||||
buf: &mut dyn Write,
|
||||
edition: Edition,
|
||||
) -> fmt::Result {
|
||||
match arg {
|
||||
GenericArg::Type(ty) => print_type_ref(db, ty, buf, edition),
|
||||
GenericArg::Type(ty) => print_type_ref(db, *ty, map, buf, edition),
|
||||
GenericArg::Const(c) => write!(buf, "{}", c.display(db.upcast(), edition)),
|
||||
GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition)),
|
||||
}
|
||||
|
|
@ -152,12 +159,13 @@ pub(crate) fn print_generic_arg(
|
|||
|
||||
pub(crate) fn print_type_ref(
|
||||
db: &dyn DefDatabase,
|
||||
type_ref: &TypeRef,
|
||||
type_ref: TypeRefId,
|
||||
map: &TypesMap,
|
||||
buf: &mut dyn Write,
|
||||
edition: Edition,
|
||||
) -> fmt::Result {
|
||||
// FIXME: deduplicate with `HirDisplay` impl
|
||||
match type_ref {
|
||||
match &map[type_ref] {
|
||||
TypeRef::Never => write!(buf, "!")?,
|
||||
TypeRef::Placeholder => write!(buf, "_")?,
|
||||
TypeRef::Tuple(fields) => {
|
||||
|
|
@ -166,48 +174,48 @@ pub(crate) fn print_type_ref(
|
|||
if i != 0 {
|
||||
write!(buf, ", ")?;
|
||||
}
|
||||
print_type_ref(db, field, buf, edition)?;
|
||||
print_type_ref(db, *field, map, buf, edition)?;
|
||||
}
|
||||
write!(buf, ")")?;
|
||||
}
|
||||
TypeRef::Path(path) => print_path(db, path, buf, edition)?,
|
||||
TypeRef::Path(path) => print_path(db, path, map, buf, edition)?,
|
||||
TypeRef::RawPtr(pointee, mtbl) => {
|
||||
let mtbl = match mtbl {
|
||||
Mutability::Shared => "*const",
|
||||
Mutability::Mut => "*mut",
|
||||
};
|
||||
write!(buf, "{mtbl} ")?;
|
||||
print_type_ref(db, pointee, buf, edition)?;
|
||||
print_type_ref(db, *pointee, map, buf, edition)?;
|
||||
}
|
||||
TypeRef::Reference(pointee, lt, mtbl) => {
|
||||
let mtbl = match mtbl {
|
||||
TypeRef::Reference(ref_) => {
|
||||
let mtbl = match ref_.mutability {
|
||||
Mutability::Shared => "",
|
||||
Mutability::Mut => "mut ",
|
||||
};
|
||||
write!(buf, "&")?;
|
||||
if let Some(lt) = lt {
|
||||
if let Some(lt) = &ref_.lifetime {
|
||||
write!(buf, "{} ", lt.name.display(db.upcast(), edition))?;
|
||||
}
|
||||
write!(buf, "{mtbl}")?;
|
||||
print_type_ref(db, pointee, buf, edition)?;
|
||||
print_type_ref(db, ref_.ty, map, buf, edition)?;
|
||||
}
|
||||
TypeRef::Array(elem, len) => {
|
||||
TypeRef::Array(array) => {
|
||||
write!(buf, "[")?;
|
||||
print_type_ref(db, elem, buf, edition)?;
|
||||
write!(buf, "; {}]", len.display(db.upcast(), edition))?;
|
||||
print_type_ref(db, array.ty, map, buf, edition)?;
|
||||
write!(buf, "; {}]", array.len.display(db.upcast(), edition))?;
|
||||
}
|
||||
TypeRef::Slice(elem) => {
|
||||
write!(buf, "[")?;
|
||||
print_type_ref(db, elem, buf, edition)?;
|
||||
print_type_ref(db, *elem, map, buf, edition)?;
|
||||
write!(buf, "]")?;
|
||||
}
|
||||
TypeRef::Fn(args_and_ret, varargs, is_unsafe, abi) => {
|
||||
TypeRef::Fn(fn_) => {
|
||||
let ((_, return_type), args) =
|
||||
args_and_ret.split_last().expect("TypeRef::Fn is missing return type");
|
||||
if *is_unsafe {
|
||||
fn_.params().split_last().expect("TypeRef::Fn is missing return type");
|
||||
if fn_.is_unsafe() {
|
||||
write!(buf, "unsafe ")?;
|
||||
}
|
||||
if let Some(abi) = abi {
|
||||
if let Some(abi) = fn_.abi() {
|
||||
buf.write_str("extern ")?;
|
||||
buf.write_str(abi.as_str())?;
|
||||
buf.write_char(' ')?;
|
||||
|
|
@ -217,16 +225,16 @@ pub(crate) fn print_type_ref(
|
|||
if i != 0 {
|
||||
write!(buf, ", ")?;
|
||||
}
|
||||
print_type_ref(db, typeref, buf, edition)?;
|
||||
print_type_ref(db, *typeref, map, buf, edition)?;
|
||||
}
|
||||
if *varargs {
|
||||
if fn_.is_varargs() {
|
||||
if !args.is_empty() {
|
||||
write!(buf, ", ")?;
|
||||
}
|
||||
write!(buf, "...")?;
|
||||
}
|
||||
write!(buf, ") -> ")?;
|
||||
print_type_ref(db, return_type, buf, edition)?;
|
||||
print_type_ref(db, *return_type, map, buf, edition)?;
|
||||
}
|
||||
TypeRef::Macro(_ast_id) => {
|
||||
write!(buf, "<macro>")?;
|
||||
|
|
@ -234,11 +242,11 @@ pub(crate) fn print_type_ref(
|
|||
TypeRef::Error => write!(buf, "{{unknown}}")?,
|
||||
TypeRef::ImplTrait(bounds) => {
|
||||
write!(buf, "impl ")?;
|
||||
print_type_bounds(db, bounds, buf, edition)?;
|
||||
print_type_bounds(db, bounds, map, buf, edition)?;
|
||||
}
|
||||
TypeRef::DynTrait(bounds) => {
|
||||
write!(buf, "dyn ")?;
|
||||
print_type_bounds(db, bounds, buf, edition)?;
|
||||
print_type_bounds(db, bounds, map, buf, edition)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -247,7 +255,8 @@ pub(crate) fn print_type_ref(
|
|||
|
||||
pub(crate) fn print_type_bounds(
|
||||
db: &dyn DefDatabase,
|
||||
bounds: &[Interned<TypeBound>],
|
||||
bounds: &[TypeBound],
|
||||
map: &TypesMap,
|
||||
buf: &mut dyn Write,
|
||||
edition: Edition,
|
||||
) -> fmt::Result {
|
||||
|
|
@ -256,13 +265,13 @@ pub(crate) fn print_type_bounds(
|
|||
write!(buf, " + ")?;
|
||||
}
|
||||
|
||||
match bound.as_ref() {
|
||||
match bound {
|
||||
TypeBound::Path(path, modifier) => {
|
||||
match modifier {
|
||||
TraitBoundModifier::None => (),
|
||||
TraitBoundModifier::Maybe => write!(buf, "?")?,
|
||||
}
|
||||
print_path(db, path, buf, edition)?;
|
||||
print_path(db, path, map, buf, edition)?;
|
||||
}
|
||||
TypeBound::ForLifetime(lifetimes, path) => {
|
||||
write!(
|
||||
|
|
@ -270,9 +279,25 @@ pub(crate) fn print_type_bounds(
|
|||
"for<{}> ",
|
||||
lifetimes.iter().map(|it| it.display(db.upcast(), edition)).format(", ")
|
||||
)?;
|
||||
print_path(db, path, buf, edition)?;
|
||||
print_path(db, path, map, buf, edition)?;
|
||||
}
|
||||
TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition))?,
|
||||
TypeBound::Use(args) => {
|
||||
write!(buf, "use<")?;
|
||||
let mut first = true;
|
||||
for arg in args {
|
||||
if !mem::take(&mut first) {
|
||||
write!(buf, ", ")?;
|
||||
}
|
||||
match arg {
|
||||
UseArgRef::Name(it) => write!(buf, "{}", it.display(db.upcast(), edition))?,
|
||||
UseArgRef::Lifetime(it) => {
|
||||
write!(buf, "{}", it.name.display(db.upcast(), edition))?
|
||||
}
|
||||
}
|
||||
}
|
||||
write!(buf, ">")?
|
||||
}
|
||||
TypeBound::Error => write!(buf, "{{unknown}}")?,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
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