1
Fork 0

Auto merge of #101895 - GuillaumeGomez:rollup-ured85q, r=GuillaumeGomez

Rollup of 7 pull requests

Successful merges:

 - #101494 (rustdoc mobile: move notable traits to return type)
 - #101813 (Extend CSS check to CSS variables)
 - #101825 (Fix back RPIT changes)
 - #101843 (Suggest associated const for incorrect use of let in traits)
 - #101859 (Slight vertical formatting)
 - #101868 (rustdoc: use more precise URLs for jump-to-definition links)
 - #101877 (rustdoc: remove no-op CSS `.block { padding: 0 }`)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-09-16 12:43:22 +00:00
commit 54f20bbb8a
20 changed files with 538 additions and 449 deletions

View file

@ -220,7 +220,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&sym.qself,
&sym.path,
ParamMode::Optional,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
hir::InlineAsmOperand::SymStatic { path, def_id }
} else {

View file

@ -84,9 +84,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
fn lower_local(&mut self, l: &Local) -> &'hir hir::Local<'hir> {
let ty = l.ty.as_ref().map(|t| {
self.lower_ty(t, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Variable))
});
let ty = l
.ty
.as_ref()
.map(|t| self.lower_ty(t, &ImplTraitContext::Disallowed(ImplTraitPosition::Variable)));
let init = l.kind.init().map(|init| self.lower_expr(init));
let hir_id = self.lower_node_id(l.id);
let pat = self.lower_pat(&l.pat);

View file

@ -66,7 +66,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
seg,
ParamMode::Optional,
ParenthesizedGenericArgs::Err,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
));
let receiver = self.lower_expr(receiver);
let args =
@ -89,14 +89,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
ExprKind::Cast(ref expr, ref ty) => {
let expr = self.lower_expr(expr);
let ty = self
.lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
let ty =
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
hir::ExprKind::Cast(expr, ty)
}
ExprKind::Type(ref expr, ref ty) => {
let expr = self.lower_expr(expr);
let ty = self
.lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
let ty =
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
hir::ExprKind::Type(expr, ty)
}
ExprKind::AddrOf(k, m, ref ohs) => {
@ -225,7 +225,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
qself,
path,
ParamMode::Optional,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
hir::ExprKind::Path(qpath)
}
@ -259,7 +259,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
&se.qself,
&se.path,
ParamMode::Optional,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
)),
self.arena
.alloc_from_iter(se.fields.iter().map(|x| self.lower_expr_field(x))),
@ -556,14 +556,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
async_gen_kind: hir::AsyncGeneratorKind,
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
) -> hir::ExprKind<'hir> {
let output =
match ret_ty {
Some(ty) => hir::FnRetTy::Return(self.lower_ty(
&ty,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock),
)),
None => hir::FnRetTy::DefaultReturn(self.lower_span(span)),
};
let output = match ret_ty {
Some(ty) => hir::FnRetTy::Return(
self.lower_ty(&ty, &ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock)),
),
None => hir::FnRetTy::DefaultReturn(self.lower_span(span)),
};
// Resume argument type. We let the compiler infer this to simplify the lowering. It is
// fully constrained by `future::from_generator`.
@ -855,22 +853,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
(body_id, generator_option)
});
self.lower_lifetime_binder(closure_id, generic_params, |lctx, bound_generic_params| {
// Lower outside new scope to preserve `is_in_loop_condition`.
let fn_decl = lctx.lower_fn_decl(decl, None, fn_decl_span, FnDeclKind::Closure, None);
let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
// Lower outside new scope to preserve `is_in_loop_condition`.
let fn_decl = self.lower_fn_decl(decl, None, fn_decl_span, FnDeclKind::Closure, None);
let c = lctx.arena.alloc(hir::Closure {
binder: binder_clause,
capture_clause,
bound_generic_params,
fn_decl,
body: body_id,
fn_decl_span: lctx.lower_span(fn_decl_span),
movability: generator_option,
});
let c = self.arena.alloc(hir::Closure {
binder: binder_clause,
capture_clause,
bound_generic_params,
fn_decl,
body: body_id,
fn_decl_span: self.lower_span(fn_decl_span),
movability: generator_option,
});
hir::ExprKind::Closure(c)
})
hir::ExprKind::Closure(c)
}
fn generator_movability_for_fn(
@ -957,24 +954,23 @@ impl<'hir> LoweringContext<'_, 'hir> {
body_id
});
self.lower_lifetime_binder(closure_id, generic_params, |lctx, bound_generic_params| {
// We need to lower the declaration outside the new scope, because we
// have to conserve the state of being inside a loop condition for the
// closure argument types.
let fn_decl =
lctx.lower_fn_decl(&outer_decl, None, fn_decl_span, FnDeclKind::Closure, None);
let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
// We need to lower the declaration outside the new scope, because we
// have to conserve the state of being inside a loop condition for the
// closure argument types.
let fn_decl =
self.lower_fn_decl(&outer_decl, None, fn_decl_span, FnDeclKind::Closure, None);
let c = lctx.arena.alloc(hir::Closure {
binder: binder_clause,
capture_clause,
bound_generic_params,
fn_decl,
body,
fn_decl_span: lctx.lower_span(fn_decl_span),
movability: None,
});
hir::ExprKind::Closure(c)
})
let c = self.arena.alloc(hir::Closure {
binder: binder_clause,
capture_clause,
bound_generic_params,
fn_decl,
body,
fn_decl_span: self.lower_span(fn_decl_span),
movability: None,
});
hir::ExprKind::Closure(c)
}
/// Destructure the LHS of complex assignments.
@ -1133,7 +1129,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
qself,
path,
ParamMode::Optional,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
// Destructure like a tuple struct.
let tuple_struct_pat = hir::PatKind::TupleStruct(
@ -1152,7 +1148,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
qself,
path,
ParamMode::Optional,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
// Destructure like a unit struct.
let unit_struct_pat = hir::PatKind::Path(qpath);
@ -1176,7 +1172,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
&se.qself,
&se.path,
ParamMode::Optional,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
let fields_omitted = match &se.rest {
StructRest::Base(e) => {

View file

@ -313,8 +313,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, ty) = self.lower_generics(
&generics,
id,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| this.lower_ty(ty, &mut ImplTraitContext::TypeAliasesOpaqueTy),
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy),
);
hir::ItemKind::TyAlias(ty, generics)
}
@ -326,7 +326,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, ty) = self.lower_generics(
&generics,
id,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| this.arena.alloc(this.ty(span, hir::TyKind::Err)),
);
hir::ItemKind::TyAlias(ty, generics)
@ -335,7 +335,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, variants) = self.lower_generics(
generics,
id,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
this.arena.alloc_from_iter(
enum_definition.variants.iter().map(|x| this.lower_variant(x)),
@ -348,7 +348,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, struct_def) = self.lower_generics(
generics,
id,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| this.lower_variant_data(hir_id, struct_def),
);
hir::ItemKind::Struct(struct_def, generics)
@ -357,7 +357,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, vdata) = self.lower_generics(
generics,
id,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| this.lower_variant_data(hir_id, vdata),
);
hir::ItemKind::Union(vdata, generics)
@ -391,14 +391,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
this.lower_trait_ref(
trait_ref,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
&ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
)
});
let lowered_ty = this.lower_ty(
ty,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Type),
);
let lowered_ty = this
.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
(trait_ref, lowered_ty)
});
@ -437,11 +435,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, (unsafety, items, bounds)) = self.lower_generics(
generics,
id,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
let bounds = this.lower_param_bounds(
bounds,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
&ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
);
let items = this.arena.alloc_from_iter(
items.iter().map(|item| this.lower_trait_item_ref(item)),
@ -456,11 +454,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, bounds) = self.lower_generics(
generics,
id,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
this.lower_param_bounds(
bounds,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
&ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
)
},
);
@ -483,7 +481,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
span: Span,
body: Option<&Expr>,
) -> (&'hir hir::Ty<'hir>, hir::BodyId) {
let ty = self.lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
(ty, self.lower_const_body(span, body))
}
@ -675,8 +673,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ForeignItemKind::Fn(fn_dec, fn_args, generics)
}
ForeignItemKind::Static(ref t, m, _) => {
let ty = self
.lower_ty(t, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
let ty =
self.lower_ty(t, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
hir::ForeignItemKind::Static(ty, m)
}
ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type,
@ -744,11 +742,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
qself,
path,
ParamMode::ExplicitNamed, // no `'_` in declarations (Issue #61124)
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
self.arena.alloc(t)
} else {
self.lower_ty(&f.ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type))
self.lower_ty(&f.ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type))
};
let hir_id = self.lower_node_id(f.id);
self.lower_attrs(hir_id, &f.attrs);
@ -771,8 +769,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, kind, has_default) = match i.kind {
AssocItemKind::Const(_, ref ty, ref default) => {
let ty =
self.lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
(hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some())
}
@ -813,18 +810,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, kind) = self.lower_generics(
&generics,
i.id,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
let ty = ty.as_ref().map(|x| {
this.lower_ty(
x,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Type),
)
this.lower_ty(x, &ImplTraitContext::Disallowed(ImplTraitPosition::Type))
});
hir::TraitItemKind::Type(
this.lower_param_bounds(
bounds,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
),
ty,
)
@ -877,8 +871,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, kind) = match &i.kind {
AssocItemKind::Const(_, ty, expr) => {
let ty =
self.lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
(
hir::Generics::empty(),
hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())),
@ -905,14 +898,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_generics(
&generics,
i.id,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| match ty {
None => {
let ty = this.arena.alloc(this.ty(i.span, hir::TyKind::Err));
hir::ImplItemKind::TyAlias(ty)
}
Some(ty) => {
let ty = this.lower_ty(ty, &mut ImplTraitContext::TypeAliasesOpaqueTy);
let ty = this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy);
hir::ImplItemKind::TyAlias(ty)
}
},
@ -1322,7 +1315,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
&mut self,
generics: &Generics,
parent_node_id: NodeId,
itctx: &mut ImplTraitContext,
itctx: &ImplTraitContext,
f: impl FnOnce(&mut Self) -> T,
) -> (&'hir hir::Generics<'hir>, T) {
debug_assert!(self.impl_trait_defs.is_empty());
@ -1427,7 +1420,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
id: NodeId,
kind: &GenericParamKind,
bounds: &[GenericBound],
itctx: &mut ImplTraitContext,
itctx: &ImplTraitContext,
origin: PredicateOrigin,
) -> Option<hir::WherePredicate<'hir>> {
// Do not create a clause if we do not have anything inside it.
@ -1502,14 +1495,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
span,
}) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
bound_generic_params: self.lower_generic_params(bound_generic_params),
bounded_ty: self.lower_ty(
bounded_ty,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Type),
),
bounded_ty: self
.lower_ty(bounded_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| {
self.lower_param_bound(
bound,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
&ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
)
})),
span: self.lower_span(span),
@ -1524,20 +1515,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
lifetime: self.lower_lifetime(lifetime),
bounds: self.lower_param_bounds(
bounds,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
&ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
),
in_where_clause: true,
}),
WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, span }) => {
hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
lhs_ty: self.lower_ty(
lhs_ty,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Type),
),
rhs_ty: self.lower_ty(
rhs_ty,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Type),
),
lhs_ty: self
.lower_ty(lhs_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
rhs_ty: self
.lower_ty(rhs_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
span: self.lower_span(span),
})
}

View file

@ -839,31 +839,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
/// name resolver owing to lifetime elision; this also populates the resolver's node-id->def-id
/// map, so that later calls to `opt_node_id_to_def_id` that refer to these extra lifetime
/// parameters will be successful.
#[instrument(level = "debug", skip(self, in_binder))]
#[instrument(level = "debug", skip(self))]
#[inline]
fn lower_lifetime_binder<R>(
fn lower_lifetime_binder(
&mut self,
binder: NodeId,
generic_params: &[GenericParam],
in_binder: impl FnOnce(&mut Self, &'hir [hir::GenericParam<'hir>]) -> R,
) -> R {
) -> &'hir [hir::GenericParam<'hir>] {
let mut generic_params: Vec<_> = self.lower_generic_params_mut(generic_params).collect();
let extra_lifetimes = self.resolver.take_extra_lifetime_params(binder);
debug!(?extra_lifetimes);
let extra_lifetimes: Vec<_> = extra_lifetimes
.into_iter()
.filter_map(|(ident, node_id, res)| {
self.lifetime_res_to_generic_param(ident, node_id, res)
})
.collect();
let generic_params: Vec<_> = self
.lower_generic_params_mut(generic_params)
.chain(extra_lifetimes.into_iter())
.collect();
generic_params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
self.lifetime_res_to_generic_param(ident, node_id, res)
}));
let generic_params = self.arena.alloc_from_iter(generic_params);
debug!(?generic_params);
in_binder(self, generic_params)
generic_params
}
fn with_dyn_type_scope<T>(&mut self, in_scope: bool, f: impl FnOnce(&mut Self) -> T) -> T {
@ -992,7 +984,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_assoc_ty_constraint(
&mut self,
constraint: &AssocConstraint,
itctx: &mut ImplTraitContext,
itctx: &ImplTraitContext,
) -> hir::TypeBinding<'hir> {
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
// lower generic arguments of identifier in constraint
@ -1011,7 +1003,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} else {
self.arena.alloc(hir::GenericArgs::none())
};
let mut itctx_tait = ImplTraitContext::TypeAliasesOpaqueTy;
let itctx_tait = &ImplTraitContext::TypeAliasesOpaqueTy;
let kind = match constraint.kind {
AssocConstraintKind::Equality { ref term } => {
@ -1049,9 +1041,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// then to an opaque type).
//
// FIXME: this is only needed until `impl Trait` is allowed in type aliases.
ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => {
(true, &mut itctx_tait)
}
ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => (true, itctx_tait),
// We are in the parameter position, but not within a dyn type:
//
@ -1130,7 +1120,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_generic_arg(
&mut self,
arg: &ast::GenericArg,
itctx: &mut ImplTraitContext,
itctx: &ImplTraitContext,
) -> hir::GenericArg<'hir> {
match arg {
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(&lt)),
@ -1192,7 +1182,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
#[instrument(level = "debug", skip(self))]
fn lower_ty(&mut self, t: &Ty, itctx: &mut ImplTraitContext) -> &'hir hir::Ty<'hir> {
fn lower_ty(&mut self, t: &Ty, itctx: &ImplTraitContext) -> &'hir hir::Ty<'hir> {
self.arena.alloc(self.lower_ty_direct(t, itctx))
}
@ -1202,7 +1192,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
qself: &Option<QSelf>,
path: &Path,
param_mode: ParamMode,
itctx: &mut ImplTraitContext,
itctx: &ImplTraitContext,
) -> hir::Ty<'hir> {
// Check whether we should interpret this as a bare trait object.
// This check mirrors the one in late resolution. We only introduce this special case in
@ -1245,7 +1235,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.ty(span, hir::TyKind::Tup(tys))
}
fn lower_ty_direct(&mut self, t: &Ty, itctx: &mut ImplTraitContext) -> hir::Ty<'hir> {
fn lower_ty_direct(&mut self, t: &Ty, itctx: &ImplTraitContext) -> hir::Ty<'hir> {
let kind = match t.kind {
TyKind::Infer => hir::TyKind::Infer,
TyKind::Err => hir::TyKind::Err,
@ -1268,15 +1258,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx))
}
TyKind::BareFn(ref f) => {
self.lower_lifetime_binder(t.id, &f.generic_params, |lctx, generic_params| {
hir::TyKind::BareFn(lctx.arena.alloc(hir::BareFnTy {
generic_params,
unsafety: lctx.lower_unsafety(f.unsafety),
abi: lctx.lower_extern(f.ext),
decl: lctx.lower_fn_decl(&f.decl, None, t.span, FnDeclKind::Pointer, None),
param_names: lctx.lower_fn_params_to_names(&f.decl),
}))
})
let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
hir::TyKind::BareFn(self.arena.alloc(hir::BareFnTy {
generic_params,
unsafety: self.lower_unsafety(f.unsafety),
abi: self.lower_extern(f.ext),
decl: self.lower_fn_decl(&f.decl, None, t.span, FnDeclKind::Pointer, None),
param_names: self.lower_fn_params_to_names(&f.decl),
}))
}
TyKind::Never => hir::TyKind::Never,
TyKind::Tup(ref tys) => hir::TyKind::Tup(
@ -1357,7 +1346,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
def_node_id,
bounds,
false,
&mut ImplTraitContext::TypeAliasesOpaqueTy,
&ImplTraitContext::TypeAliasesOpaqueTy,
),
ImplTraitContext::Universal => {
let span = t.span;
@ -1444,7 +1433,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
opaque_ty_node_id: NodeId,
bounds: &GenericBounds,
in_trait: bool,
itctx: &mut ImplTraitContext,
itctx: &ImplTraitContext,
) -> hir::TyKind<'hir> {
// Make sure we know that some funky desugaring has been going on here.
// This is a first: there is code in other places like for loop
@ -1690,11 +1679,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| {
if fn_node_id.is_some() {
self.lower_ty_direct(&param.ty, &mut ImplTraitContext::Universal)
self.lower_ty_direct(&param.ty, &ImplTraitContext::Universal)
} else {
self.lower_ty_direct(
&param.ty,
&mut ImplTraitContext::Disallowed(match kind {
&ImplTraitContext::Disallowed(match kind {
FnDeclKind::Fn | FnDeclKind::Inherent => {
unreachable!("fn should allow in-band lifetimes")
}
@ -2093,7 +2082,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_param_bound(
&mut self,
tpb: &GenericBound,
itctx: &mut ImplTraitContext,
itctx: &ImplTraitContext,
) -> hir::GenericBound<'hir> {
match tpb {
GenericBound::Trait(p, modifier) => hir::GenericBound::Trait(
@ -2209,7 +2198,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
GenericParamKind::Type { ref default, .. } => {
let kind = hir::GenericParamKind::Type {
default: default.as_ref().map(|x| {
self.lower_ty(x, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type))
self.lower_ty(x, &ImplTraitContext::Disallowed(ImplTraitPosition::Type))
}),
synthetic: false,
};
@ -2217,8 +2206,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
(hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
}
GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
let ty =
self.lower_ty(&ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
let ty = self.lower_ty(&ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
let default = default.as_ref().map(|def| self.lower_anon_const(def));
(
hir::ParamName::Plain(self.lower_ident(param.ident)),
@ -2228,11 +2216,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
}
fn lower_trait_ref(
&mut self,
p: &TraitRef,
itctx: &mut ImplTraitContext,
) -> hir::TraitRef<'hir> {
fn lower_trait_ref(&mut self, p: &TraitRef, itctx: &ImplTraitContext) -> hir::TraitRef<'hir> {
let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) {
hir::QPath::Resolved(None, path) => path,
qpath => panic!("lower_trait_ref: unexpected QPath `{:?}`", qpath),
@ -2244,19 +2228,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_poly_trait_ref(
&mut self,
p: &PolyTraitRef,
itctx: &mut ImplTraitContext,
itctx: &ImplTraitContext,
) -> hir::PolyTraitRef<'hir> {
self.lower_lifetime_binder(
p.trait_ref.ref_id,
&p.bound_generic_params,
|lctx, bound_generic_params| {
let trait_ref = lctx.lower_trait_ref(&p.trait_ref, itctx);
hir::PolyTraitRef { bound_generic_params, trait_ref, span: lctx.lower_span(p.span) }
},
)
let bound_generic_params =
self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
let trait_ref = self.lower_trait_ref(&p.trait_ref, itctx);
hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
}
fn lower_mt(&mut self, mt: &MutTy, itctx: &mut ImplTraitContext) -> hir::MutTy<'hir> {
fn lower_mt(&mut self, mt: &MutTy, itctx: &ImplTraitContext) -> hir::MutTy<'hir> {
hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl }
}
@ -2264,17 +2244,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_param_bounds(
&mut self,
bounds: &[GenericBound],
itctx: &mut ImplTraitContext,
itctx: &ImplTraitContext,
) -> hir::GenericBounds<'hir> {
self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, itctx))
}
fn lower_param_bounds_mut<'s, 'b>(
fn lower_param_bounds_mut<'s>(
&'s mut self,
bounds: &'s [GenericBound],
itctx: &'b mut ImplTraitContext,
) -> impl Iterator<Item = hir::GenericBound<'hir>> + Captures<'s> + Captures<'a> + Captures<'b>
{
itctx: &'s ImplTraitContext,
) -> impl Iterator<Item = hir::GenericBound<'hir>> + Captures<'s> + Captures<'a> {
bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx))
}
@ -2304,7 +2283,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
node_id,
&GenericParamKind::Type { default: None },
bounds,
&mut ImplTraitContext::Universal,
&ImplTraitContext::Universal,
hir::PredicateOrigin::ImplTrait,
);

View file

@ -22,7 +22,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
qself: &Option<QSelf>,
p: &Path,
param_mode: ParamMode,
itctx: &mut ImplTraitContext,
itctx: &ImplTraitContext,
) -> hir::QPath<'hir> {
let qself_position = qself.as_ref().map(|q| q.position);
let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
@ -156,7 +156,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
segment,
param_mode,
ParenthesizedGenericArgs::Err,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
)
})),
span: self.lower_span(p.span),
@ -180,7 +180,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
segment: &PathSegment,
param_mode: ParamMode,
parenthesized_generic_args: ParenthesizedGenericArgs,
itctx: &mut ImplTraitContext,
itctx: &ImplTraitContext,
) -> hir::PathSegment<'hir> {
debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,);
let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args {
@ -316,7 +316,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&mut self,
data: &AngleBracketedArgs,
param_mode: ParamMode,
itctx: &mut ImplTraitContext,
itctx: &ImplTraitContext,
) -> (GenericArgsCtor<'hir>, bool) {
let has_non_lt_args = data.args.iter().any(|arg| match arg {
AngleBracketedArg::Arg(ast::GenericArg::Lifetime(_))
@ -350,14 +350,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// we generally don't permit such things (see #51008).
let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| {
self.lower_ty_direct(
ty,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam),
)
self.lower_ty_direct(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
}));
let output_ty = match output {
FnRetTy::Ty(ty) => self
.lower_ty(&ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)),
FnRetTy::Ty(ty) => {
self.lower_ty(&ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
}
FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
};
let args = smallvec![GenericArg::Type(self.arena.alloc(self.ty_tup(*inputs_span, inputs)))];

View file

@ -698,11 +698,22 @@ impl<'a> Parser<'a> {
let semicolon_span = self.token.span;
// We have to bail or we'll potentially never make progress.
let non_item_span = self.token.span;
self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
let is_let = self.token.is_keyword(kw::Let);
let mut err = self.struct_span_err(non_item_span, "non-item in item list");
err.span_label(open_brace_span, "item list starts here")
.span_label(non_item_span, "non-item starts here")
.span_label(self.prev_token.span, "item list ends here");
self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
if is_let {
err.span_suggestion(
non_item_span,
"consider using `const` instead of `let` for associated const",
"const",
Applicability::MachineApplicable,
);
} else {
err.span_label(open_brace_span, "item list starts here")
.span_label(non_item_span, "non-item starts here")
.span_label(self.prev_token.span, "item list ends here");
}
if is_unnecessary_semicolon {
err.span_suggestion(
semicolon_span,

View file

@ -66,18 +66,18 @@ impl<'a> Parser<'a> {
},
NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => {
match token.kind {
token::Ident(..) | // box, ref, mut, and other identifiers (can stricten)
token::OpenDelim(Delimiter::Parenthesis) | // tuple pattern
token::OpenDelim(Delimiter::Bracket) | // slice pattern
token::BinOp(token::And) | // reference
token::BinOp(token::Minus) | // negative literal
token::AndAnd | // double reference
token::Literal(..) | // literal
token::DotDot | // range pattern (future compat)
token::DotDotDot | // range pattern (future compat)
token::ModSep | // path
token::Lt | // path (UFCS constant)
token::BinOp(token::Shl) => true, // path (double UFCS)
token::Ident(..) | // box, ref, mut, and other identifiers (can stricten)
token::OpenDelim(Delimiter::Parenthesis) | // tuple pattern
token::OpenDelim(Delimiter::Bracket) | // slice pattern
token::BinOp(token::And) | // reference
token::BinOp(token::Minus) | // negative literal
token::AndAnd | // double reference
token::Literal(..) | // literal
token::DotDot | // range pattern (future compat)
token::DotDotDot | // range pattern (future compat)
token::ModSep | // path
token::Lt | // path (UFCS constant)
token::BinOp(token::Shl) => true, // path (double UFCS)
// leading vert `|` or-pattern
token::BinOp(token::Or) => matches!(kind, NonterminalKind::PatWithOr {..}),
token::Interpolated(ref nt) => may_be_ident(nt),

View file

@ -412,7 +412,13 @@ impl Options {
let to_check = matches.opt_strs("check-theme");
if !to_check.is_empty() {
let paths = theme::load_css_paths(static_files::themes::LIGHT.as_bytes());
let paths = match theme::load_css_paths(static_files::themes::LIGHT) {
Ok(p) => p,
Err(e) => {
diag.struct_err(&e.to_string()).emit();
return Err(1);
}
};
let mut errors = 0;
println!("rustdoc: [check-theme] Starting tests! (Ignoring all other arguments)");
@ -547,7 +553,13 @@ impl Options {
let mut themes = Vec::new();
if matches.opt_present("theme") {
let paths = theme::load_css_paths(static_files::themes::LIGHT.as_bytes());
let paths = match theme::load_css_paths(static_files::themes::LIGHT) {
Ok(p) => p,
Err(e) => {
diag.struct_err(&e.to_string()).emit();
return Err(1);
}
};
for (theme_file, theme_s) in
matches.opt_strs("theme").iter().map(|s| (PathBuf::from(&s), s.to_owned()))

View file

@ -29,6 +29,8 @@ pub(crate) struct HrefContext<'a, 'b, 'c> {
/// This field is used to know "how far" from the top of the directory we are to link to either
/// documentation pages or other source pages.
pub(crate) root_path: &'c str,
/// This field is used to calculate precise local URLs.
pub(crate) current_href: &'c str,
}
/// Decorations are represented as a map from CSS class to vector of character ranges.
@ -977,9 +979,9 @@ fn string_without_closing_tag<T: Display>(
// a link to their definition can be generated using this:
// https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
match href {
LinkFromSrc::Local(span) => context
.href_from_span(*span, true)
.map(|s| format!("{}{}", href_context.root_path, s)),
LinkFromSrc::Local(span) => {
context.href_from_span_relative(*span, href_context.current_href)
}
LinkFromSrc::External(def_id) => {
format::href_with_root_path(*def_id, context, Some(href_context.root_path))
.ok()

View file

@ -31,6 +31,7 @@ use crate::formats::FormatRenderer;
use crate::html::escape::Escape;
use crate::html::format::{join_with_double_colon, Buffer};
use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap};
use crate::html::url_parts_builder::UrlPartsBuilder;
use crate::html::{layout, sources};
use crate::scrape_examples::AllCallLocations;
use crate::try_err;
@ -370,6 +371,35 @@ impl<'tcx> Context<'tcx> {
anchor = anchor
))
}
pub(crate) fn href_from_span_relative(
&self,
span: clean::Span,
relative_to: &str,
) -> Option<String> {
self.href_from_span(span, false).map(|s| {
let mut url = UrlPartsBuilder::new();
let mut dest_href_parts = s.split('/');
let mut cur_href_parts = relative_to.split('/');
for (cur_href_part, dest_href_part) in (&mut cur_href_parts).zip(&mut dest_href_parts) {
if cur_href_part != dest_href_part {
url.push(dest_href_part);
break;
}
}
for dest_href_part in dest_href_parts {
url.push(dest_href_part);
}
let loline = span.lo(self.sess()).line;
let hiline = span.hi(self.sess()).line;
format!(
"{}{}#{}",
"../".repeat(cur_href_parts.count()),
url.finish(),
if loline == hiline { loline.to_string() } else { format!("{loline}-{hiline}") }
)
})
}
}
/// Generates the documentation for `crate` into the directory `dst`

View file

@ -288,11 +288,14 @@ pub(crate) fn print_src(
}
}
line_numbers.write_str("</pre>");
let current_href = &context
.href_from_span(clean::Span::new(file_span), false)
.expect("only local crates should have sources emitted");
highlight::render_source_with_highlighting(
s,
buf,
line_numbers,
highlight::HrefContext { context, file_span, root_path },
highlight::HrefContext { context, file_span, root_path, current_href },
decoration_info,
);
}

View file

@ -497,9 +497,6 @@ img {
font-weight: 500;
}
.block {
padding: 0;
}
.block ul, .block li {
padding: 0;
margin: 0;
@ -1865,12 +1862,6 @@ in storage.js plus the media query with (min-width: 701px)
display: none !important;
}
.notable-traits {
position: absolute;
left: -22px;
top: 24px;
}
#titles > button > div.count {
display: block;
}

View file

@ -1,271 +1,252 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::fx::FxHashMap;
use std::collections::hash_map::Entry;
use std::fs;
use std::hash::{Hash, Hasher};
use std::iter::Peekable;
use std::path::Path;
use std::str::Chars;
use rustc_errors::Handler;
#[cfg(test)]
mod tests;
#[derive(Debug, Clone, Eq)]
#[derive(Debug)]
pub(crate) struct CssPath {
pub(crate) name: String,
pub(crate) children: FxHashSet<CssPath>,
pub(crate) rules: FxHashMap<String, String>,
pub(crate) children: FxHashMap<String, CssPath>,
}
// This PartialEq implementation IS NOT COMMUTATIVE!!!
//
// The order is very important: the second object must have all first's rules.
// However, the first is not required to have all of the second's rules.
impl PartialEq for CssPath {
fn eq(&self, other: &CssPath) -> bool {
if self.name != other.name {
false
} else {
for child in &self.children {
if !other.children.iter().any(|c| child == c) {
return false;
}
}
true
/// When encountering a `"` or a `'`, returns the whole string, including the quote characters.
fn get_string(iter: &mut Peekable<Chars<'_>>, string_start: char, buffer: &mut String) {
buffer.push(string_start);
while let Some(c) = iter.next() {
buffer.push(c);
if c == '\\' {
iter.next();
} else if c == string_start {
break;
}
}
}
impl Hash for CssPath {
fn hash<H: Hasher>(&self, state: &mut H) {
self.name.hash(state);
for x in &self.children {
x.hash(state);
fn get_inside_paren(
iter: &mut Peekable<Chars<'_>>,
paren_start: char,
paren_end: char,
buffer: &mut String,
) {
buffer.push(paren_start);
while let Some(c) = iter.next() {
handle_common_chars(c, buffer, iter);
if c == paren_end {
break;
}
}
}
impl CssPath {
fn new(name: String) -> CssPath {
CssPath { name, children: FxHashSet::default() }
}
}
/// All variants contain the position they occur.
#[derive(Debug, Clone, Copy)]
enum Events {
StartLineComment(usize),
StartComment(usize),
EndComment(usize),
InBlock(usize),
OutBlock(usize),
}
impl Events {
fn get_pos(&self) -> usize {
match *self {
Events::StartLineComment(p)
| Events::StartComment(p)
| Events::EndComment(p)
| Events::InBlock(p)
| Events::OutBlock(p) => p,
/// Skips a `/*` comment.
fn skip_comment(iter: &mut Peekable<Chars<'_>>) {
while let Some(c) = iter.next() {
if c == '*' && iter.next() == Some('/') {
break;
}
}
fn is_comment(&self) -> bool {
matches!(
self,
Events::StartLineComment(_) | Events::StartComment(_) | Events::EndComment(_)
)
}
}
fn previous_is_line_comment(events: &[Events]) -> bool {
matches!(events.last(), Some(&Events::StartLineComment(_)))
}
fn is_line_comment(pos: usize, v: &[u8], events: &[Events]) -> bool {
if let Some(&Events::StartComment(_)) = events.last() {
return false;
}
v[pos + 1] == b'/'
}
fn load_css_events(v: &[u8]) -> Vec<Events> {
let mut pos = 0;
let mut events = Vec::with_capacity(100);
while pos + 1 < v.len() {
match v[pos] {
b'/' if v[pos + 1] == b'*' => {
events.push(Events::StartComment(pos));
pos += 1;
}
b'/' if is_line_comment(pos, v, &events) => {
events.push(Events::StartLineComment(pos));
pos += 1;
}
b'\n' if previous_is_line_comment(&events) => {
events.push(Events::EndComment(pos));
}
b'*' if v[pos + 1] == b'/' => {
events.push(Events::EndComment(pos + 2));
pos += 1;
}
b'{' if !previous_is_line_comment(&events) => {
if let Some(&Events::StartComment(_)) = events.last() {
pos += 1;
continue;
}
events.push(Events::InBlock(pos + 1));
}
b'}' if !previous_is_line_comment(&events) => {
if let Some(&Events::StartComment(_)) = events.last() {
pos += 1;
continue;
}
events.push(Events::OutBlock(pos + 1));
}
_ => {}
/// Skips a line comment (`//`).
fn skip_line_comment(iter: &mut Peekable<Chars<'_>>) {
while let Some(c) = iter.next() {
if c == '\n' {
break;
}
pos += 1;
}
events
}
fn get_useful_next(events: &[Events], pos: &mut usize) -> Option<Events> {
while *pos < events.len() {
if !events[*pos].is_comment() {
return Some(events[*pos]);
fn handle_common_chars(c: char, buffer: &mut String, iter: &mut Peekable<Chars<'_>>) {
match c {
'"' | '\'' => get_string(iter, c, buffer),
'/' if iter.peek() == Some(&'*') => skip_comment(iter),
'/' if iter.peek() == Some(&'/') => skip_line_comment(iter),
'(' => get_inside_paren(iter, c, ')', buffer),
'[' => get_inside_paren(iter, c, ']', buffer),
_ => buffer.push(c),
}
}
/// Returns a CSS property name. Ends when encountering a `:` character.
///
/// If the `:` character isn't found, returns `None`.
///
/// If a `{` character is encountered, returns an error.
fn parse_property_name(iter: &mut Peekable<Chars<'_>>) -> Result<Option<String>, String> {
let mut content = String::new();
while let Some(c) = iter.next() {
match c {
':' => return Ok(Some(content.trim().to_owned())),
'{' => return Err("Unexpected `{` in a `{}` block".to_owned()),
'}' => break,
_ => handle_common_chars(c, &mut content, iter),
}
*pos += 1;
}
None
Ok(None)
}
fn get_previous_positions(events: &[Events], mut pos: usize) -> Vec<usize> {
let mut ret = Vec::with_capacity(3);
/// Try to get the value of a CSS property (the `#fff` in `color: #fff`). It'll stop when it
/// encounters a `{` or a `;` character.
///
/// It returns the value string and a boolean set to `true` if the value is ended with a `}` because
/// it means that the parent block is done and that we should notify the parent caller.
fn parse_property_value(iter: &mut Peekable<Chars<'_>>) -> (String, bool) {
let mut value = String::new();
let mut out_block = false;
ret.push(events[pos].get_pos());
if pos > 0 {
pos -= 1;
while let Some(c) = iter.next() {
match c {
';' => break,
'}' => {
out_block = true;
break;
}
_ => handle_common_chars(c, &mut value, iter),
}
}
(value.trim().to_owned(), out_block)
}
/// This is used to parse inside a CSS `{}` block. If we encounter a new `{` inside it, we consider
/// it as a new block and therefore recurse into `parse_rules`.
fn parse_rules(
content: &str,
selector: String,
iter: &mut Peekable<Chars<'_>>,
paths: &mut FxHashMap<String, CssPath>,
) -> Result<(), String> {
let mut rules = FxHashMap::default();
let mut children = FxHashMap::default();
loop {
if pos < 1 || !events[pos].is_comment() {
let x = events[pos].get_pos();
if *ret.last().unwrap() != x {
ret.push(x);
} else {
ret.push(0);
}
// If the parent isn't a "normal" CSS selector, we only expect sub-selectors and not CSS
// properties.
if selector.starts_with('@') {
parse_selectors(content, iter, &mut children)?;
break;
}
ret.push(events[pos].get_pos());
pos -= 1;
}
if ret.len() & 1 != 0 && events[pos].is_comment() {
ret.push(0);
}
ret.iter().rev().cloned().collect()
}
fn build_rule(v: &[u8], positions: &[usize]) -> String {
minifier::css::minify(
&positions
.chunks(2)
.map(|x| ::std::str::from_utf8(&v[x[0]..x[1]]).unwrap_or(""))
.collect::<String>()
.trim()
.chars()
.filter_map(|c| match c {
'\n' | '\t' => Some(' '),
'/' | '{' | '}' => None,
c => Some(c),
})
.collect::<String>()
.split(' ')
.filter(|s| !s.is_empty())
.intersperse(" ")
.collect::<String>(),
)
.map(|css| css.to_string())
.unwrap_or_else(|_| String::new())
}
fn inner(v: &[u8], events: &[Events], pos: &mut usize) -> FxHashSet<CssPath> {
let mut paths = Vec::with_capacity(50);
while *pos < events.len() {
if let Some(Events::OutBlock(_)) = get_useful_next(events, pos) {
*pos += 1;
break;
}
if let Some(Events::InBlock(_)) = get_useful_next(events, pos) {
paths.push(CssPath::new(build_rule(v, &get_previous_positions(events, *pos))));
*pos += 1;
}
while let Some(Events::InBlock(_)) = get_useful_next(events, pos) {
if let Some(ref mut path) = paths.last_mut() {
for entry in inner(v, events, pos).iter() {
path.children.insert(entry.clone());
let rule = match parse_property_name(iter)? {
Some(r) => {
if r.is_empty() {
return Err(format!("Found empty rule in selector `{selector}`"));
}
r
}
None => break,
};
let (value, out_block) = parse_property_value(iter);
if value.is_empty() {
return Err(format!("Found empty value for rule `{rule}` in selector `{selector}`"));
}
match rules.entry(rule) {
Entry::Occupied(mut o) => {
*o.get_mut() = value;
}
Entry::Vacant(v) => {
v.insert(value);
}
}
if let Some(Events::OutBlock(_)) = get_useful_next(events, pos) {
*pos += 1;
if out_block {
break;
}
}
paths.iter().cloned().collect()
match paths.entry(selector) {
Entry::Occupied(mut o) => {
let v = o.get_mut();
for (key, value) in rules.into_iter() {
v.rules.insert(key, value);
}
for (sel, child) in children.into_iter() {
v.children.insert(sel, child);
}
}
Entry::Vacant(v) => {
v.insert(CssPath { rules, children });
}
}
Ok(())
}
pub(crate) fn load_css_paths(v: &[u8]) -> CssPath {
let events = load_css_events(v);
let mut pos = 0;
pub(crate) fn parse_selectors(
content: &str,
iter: &mut Peekable<Chars<'_>>,
paths: &mut FxHashMap<String, CssPath>,
) -> Result<(), String> {
let mut selector = String::new();
let mut parent = CssPath::new("parent".to_owned());
parent.children = inner(v, &events, &mut pos);
parent
while let Some(c) = iter.next() {
match c {
'{' => {
let s = minifier::css::minify(selector.trim()).map(|s| s.to_string())?;
parse_rules(content, s, iter, paths)?;
selector.clear();
}
'}' => break,
';' => selector.clear(), // We don't handle inline selectors like `@import`.
_ => handle_common_chars(c, &mut selector, iter),
}
}
Ok(())
}
pub(crate) fn get_differences(against: &CssPath, other: &CssPath, v: &mut Vec<String>) {
if against.name == other.name {
for child in &against.children {
let mut found = false;
let mut found_working = false;
let mut tmp = Vec::new();
/// The entry point to parse the CSS rules. Every time we encounter a `{`, we then parse the rules
/// inside it.
pub(crate) fn load_css_paths(content: &str) -> Result<FxHashMap<String, CssPath>, String> {
let mut iter = content.chars().peekable();
let mut paths = FxHashMap::default();
for other_child in &other.children {
if child.name == other_child.name {
if child != other_child {
get_differences(child, other_child, &mut tmp);
} else {
found_working = true;
parse_selectors(content, &mut iter, &mut paths)?;
Ok(paths)
}
pub(crate) fn get_differences(
origin: &FxHashMap<String, CssPath>,
against: &FxHashMap<String, CssPath>,
v: &mut Vec<String>,
) {
for (selector, entry) in origin.iter() {
match against.get(selector) {
Some(a) => {
get_differences(&entry.children, &a.children, v);
if selector == ":root" {
// We need to check that all variables have been set.
for rule in entry.rules.keys() {
if !a.rules.contains_key(rule) {
v.push(format!(" Missing CSS variable `{rule}` in `:root`"));
}
}
found = true;
break;
}
}
if !found {
v.push(format!(" Missing \"{}\" rule", child.name));
} else if !found_working {
v.extend(tmp.iter().cloned());
}
None => v.push(format!(" Missing rule `{selector}`")),
}
}
}
pub(crate) fn test_theme_against<P: AsRef<Path>>(
f: &P,
against: &CssPath,
origin: &FxHashMap<String, CssPath>,
diag: &Handler,
) -> (bool, Vec<String>) {
let data = match fs::read(f) {
let against = match fs::read_to_string(f)
.map_err(|e| e.to_string())
.and_then(|data| load_css_paths(&data))
{
Ok(c) => c,
Err(e) => {
diag.struct_err(&e.to_string()).emit();
diag.struct_err(&e).emit();
return (false, vec![]);
}
};
let paths = load_css_paths(&data);
let mut ret = vec![];
get_differences(against, &paths, &mut ret);
get_differences(origin, &against, &mut ret);
(true, ret)
}

View file

@ -44,11 +44,7 @@ rule j end {}
"#;
let mut ret = Vec::new();
get_differences(
&load_css_paths(against.as_bytes()),
&load_css_paths(text.as_bytes()),
&mut ret,
);
get_differences(&load_css_paths(against).unwrap(), &load_css_paths(text).unwrap(), &mut ret);
assert!(ret.is_empty());
}
@ -61,46 +57,45 @@ a
c // sdf
d {}
"#;
let paths = load_css_paths(text.as_bytes());
assert!(paths.children.contains(&CssPath::new("a b c d".to_owned())));
let paths = load_css_paths(text).unwrap();
assert!(paths.contains_key(&"a b c d".to_owned()));
}
#[test]
fn test_comparison() {
let x = r#"
a {
b {
c {}
}
let origin = r#"
@a {
b {}
c {}
}
"#;
let y = r#"
a {
let against = r#"
@a {
b {}
}
"#;
let against = load_css_paths(y.as_bytes());
let other = load_css_paths(x.as_bytes());
let origin = load_css_paths(origin).unwrap();
let against = load_css_paths(against).unwrap();
let mut ret = Vec::new();
get_differences(&against, &other, &mut ret);
get_differences(&against, &origin, &mut ret);
assert!(ret.is_empty());
get_differences(&other, &against, &mut ret);
assert_eq!(ret, vec![" Missing \"c\" rule".to_owned()]);
get_differences(&origin, &against, &mut ret);
assert_eq!(ret, vec![" Missing rule `c`".to_owned()]);
}
#[test]
fn check_empty_css() {
let events = load_css_events(&[]);
assert_eq!(events.len(), 0);
let paths = load_css_paths("").unwrap();
assert_eq!(paths.len(), 0);
}
#[test]
fn check_invalid_css() {
let events = load_css_events(b"*");
assert_eq!(events.len(), 0);
let paths = load_css_paths("*").unwrap();
assert_eq!(paths.len(), 0);
}
#[test]
@ -108,10 +103,85 @@ fn test_with_minification() {
let text = include_str!("../html/static/css/themes/dark.css");
let minified = minifier::css::minify(&text).expect("CSS minification failed").to_string();
let against = load_css_paths(text.as_bytes());
let other = load_css_paths(minified.as_bytes());
let against = load_css_paths(text).unwrap();
let other = load_css_paths(&minified).unwrap();
let mut ret = Vec::new();
get_differences(&against, &other, &mut ret);
assert!(ret.is_empty());
}
#[test]
fn test_media() {
let text = r#"
@media (min-width: 701px) {
a:hover {
color: #fff;
}
b {
x: y;
}
}
@media (max-width: 1001px) {
b {
x: y;
}
}
"#;
let paths = load_css_paths(text).unwrap();
let p = paths.get("@media (min-width:701px)");
assert!(p.is_some());
let p = p.unwrap();
assert!(p.children.get("a:hover").is_some());
assert!(p.children.get("b").is_some());
let p = paths.get("@media (max-width:1001px)");
assert!(p.is_some());
let p = p.unwrap();
assert!(p.children.get("b").is_some());
}
#[test]
fn test_css_variables() {
let x = r#"
:root {
--a: #fff;
}
"#;
let y = r#"
:root {
--a: #fff;
--b: #fff;
}
"#;
let against = load_css_paths(x).unwrap();
let other = load_css_paths(y).unwrap();
let mut ret = Vec::new();
get_differences(&against, &other, &mut ret);
assert!(ret.is_empty());
get_differences(&other, &against, &mut ret);
assert_eq!(ret, vec![" Missing CSS variable `--b` in `:root`".to_owned()]);
}
#[test]
fn test_weird_rule_value() {
let x = r#"
a[text=("a")] {
b: url({;}.png);
c: #fff
}
"#;
let paths = load_css_paths(&x).unwrap();
let p = paths.get("a[text=(\"a\")]");
assert!(p.is_some());
let p = p.unwrap();
assert_eq!(p.rules.get("b"), Some(&"url({;}.png)".to_owned()));
assert_eq!(p.rules.get("c"), Some(&"#fff".to_owned()));
}

View file

@ -9,7 +9,7 @@ fn babar() {}
// @has - '//a[@href="{{channel}}/std/primitive.u32.html"]' 'u32'
// @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'str'
// @has - '//a[@href="{{channel}}/std/primitive.bool.html"]' 'bool'
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#7"]' 'babar'
// @has - '//a[@href="#7"]' 'babar'
pub fn foo(a: u32, b: &str, c: String) {
let x = 12;
let y: bool = true;
@ -31,12 +31,12 @@ macro_rules! data {
pub fn another_foo() {
// This is known limitation: if the macro doesn't generate anything, the visitor
// can't find any item or anything that could tell us that it comes from expansion.
// @!has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#19"]' 'yolo!'
// @!has - '//a[@href="#19"]' 'yolo!'
yolo!();
// @has - '//a[@href="{{channel}}/std/macro.eprintln.html"]' 'eprintln!'
eprintln!();
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#27-29"]' 'data!'
// @has - '//a[@href="#27-29"]' 'data!'
let x = data!(4);
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#23-25"]' 'bar!'
// @has - '//a[@href="#23-25"]' 'bar!'
bar!(x);
}

View file

@ -10,14 +10,14 @@ extern crate source_code;
// @has 'src/foo/check-source-code-urls-to-def.rs.html'
// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#1-17"]' 'bar'
// @has - '//a[@href="auxiliary/source-code-bar.rs.html#1-17"]' 'bar'
#[path = "auxiliary/source-code-bar.rs"]
pub mod bar;
// @count - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#5"]' 4
// @count - '//a[@href="auxiliary/source-code-bar.rs.html#5"]' 4
use bar::Bar;
// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#13"]' 'self'
// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14"]' 'Trait'
// @has - '//a[@href="auxiliary/source-code-bar.rs.html#13"]' 'self'
// @has - '//a[@href="auxiliary/source-code-bar.rs.html#14"]' 'Trait'
use bar::sub::{self, Trait};
pub struct Foo;
@ -31,26 +31,26 @@ fn babar() {}
// @has - '//a/@href' '/struct.String.html'
// @has - '//a/@href' '/primitive.u32.html'
// @has - '//a/@href' '/primitive.str.html'
// @count - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#23"]' 5
// @count - '//a[@href="#23"]' 5
// @has - '//a[@href="../../source_code/struct.SourceCode.html"]' 'source_code::SourceCode'
pub fn foo(a: u32, b: &str, c: String, d: Foo, e: bar::Bar, f: source_code::SourceCode) {
let x = 12;
let y: Foo = Foo;
let z: Bar = bar::Bar { field: Foo };
babar();
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#26"]' 'hello'
// @has - '//a[@href="#26"]' 'hello'
y.hello();
}
// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14"]' 'bar::sub::Trait'
// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14"]' 'Trait'
// @has - '//a[@href="auxiliary/source-code-bar.rs.html#14"]' 'bar::sub::Trait'
// @has - '//a[@href="auxiliary/source-code-bar.rs.html#14"]' 'Trait'
pub fn foo2<T: bar::sub::Trait, V: Trait>(t: &T, v: &V, b: bool) {}
pub trait AnotherTrait {}
pub trait WhyNot {}
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#49"]' 'AnotherTrait'
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#50"]' 'WhyNot'
// @has - '//a[@href="#49"]' 'AnotherTrait'
// @has - '//a[@href="#50"]' 'WhyNot'
pub fn foo3<T, V>(t: &T, v: &V)
where
T: AnotherTrait,
@ -59,7 +59,7 @@ where
pub trait AnotherTrait2 {}
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#60"]' 'AnotherTrait2'
// @has - '//a[@href="#60"]' 'AnotherTrait2'
pub fn foo4() {
let x: Vec<AnotherTrait2> = Vec::new();
}

View file

@ -0,0 +1,10 @@
// Issue: 101797, Suggest associated const for incorrect use of let in traits
// run-rustfix
trait Trait {
const _X: i32;
//~^ ERROR non-item in item list
}
fn main() {
}

View file

@ -0,0 +1,10 @@
// Issue: 101797, Suggest associated const for incorrect use of let in traits
// run-rustfix
trait Trait {
let _X: i32;
//~^ ERROR non-item in item list
}
fn main() {
}

View file

@ -0,0 +1,8 @@
error: non-item in item list
--> $DIR/suggest-assoc-const.rs:4:5
|
LL | let _X: i32;
| ^^^ help: consider using `const` instead of `let` for associated const: `const`
error: aborting due to previous error