Merge branch 'rust-lang:master' into issue-98861-fix

This commit is contained in:
Dan Vail 2022-08-09 12:52:11 -05:00 committed by GitHub
commit 0436067210
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
162 changed files with 3121 additions and 973 deletions

View File

@ -4626,6 +4626,7 @@ dependencies = [
"rustc_attr",
"rustc_data_structures",
"rustc_errors",
"rustc_feature",
"rustc_graphviz",
"rustc_hir",
"rustc_hir_pretty",

View File

@ -417,6 +417,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|| attr.has_name(sym::stable)
|| attr.has_name(sym::rustc_const_unstable)
|| attr.has_name(sym::rustc_const_stable)
|| attr.has_name(sym::rustc_default_body_unstable)
{
struct_span_err!(
self.sess,

View File

@ -131,6 +131,14 @@ impl ConstStability {
}
}
/// Represents the `#[rustc_default_body_unstable]` attribute.
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(HashStable_Generic)]
pub struct DefaultBodyStability {
pub level: StabilityLevel,
pub feature: Symbol,
}
/// The available stability levels.
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
#[derive(HashStable_Generic)]
@ -214,7 +222,8 @@ pub fn find_stability(
sess: &Session,
attrs: &[Attribute],
item_sp: Span,
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>) {
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>)
{
find_stability_generic(sess, attrs.iter(), item_sp)
}
@ -222,7 +231,7 @@ fn find_stability_generic<'a, I>(
sess: &Session,
attrs_iter: I,
item_sp: Span,
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>)
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>)
where
I: Iterator<Item = &'a Attribute>,
{
@ -230,6 +239,7 @@ where
let mut stab: Option<(Stability, Span)> = None;
let mut const_stab: Option<(ConstStability, Span)> = None;
let mut body_stab: Option<(DefaultBodyStability, Span)> = None;
let mut promotable = false;
let mut allowed_through_unstable_modules = false;
@ -243,6 +253,7 @@ where
sym::stable,
sym::rustc_promotable,
sym::rustc_allowed_through_unstable_modules,
sym::rustc_default_body_unstable,
]
.iter()
.any(|&s| attr.has_name(s))
@ -280,7 +291,7 @@ where
let meta_name = meta.name_or_empty();
match meta_name {
sym::rustc_const_unstable | sym::unstable => {
sym::rustc_const_unstable | sym::rustc_default_body_unstable | sym::unstable => {
if meta_name == sym::unstable && stab.is_some() {
handle_errors(
&sess.parse_sess,
@ -295,6 +306,13 @@ where
AttrError::MultipleStabilityLevels,
);
break;
} else if meta_name == sym::rustc_default_body_unstable && body_stab.is_some() {
handle_errors(
&sess.parse_sess,
attr.span,
AttrError::MultipleStabilityLevels,
);
break;
}
let mut feature = None;
@ -405,11 +423,16 @@ where
};
if sym::unstable == meta_name {
stab = Some((Stability { level, feature }, attr.span));
} else {
} else if sym::rustc_const_unstable == meta_name {
const_stab = Some((
ConstStability { level, feature, promotable: false },
attr.span,
));
} else if sym::rustc_default_body_unstable == meta_name {
body_stab =
Some((DefaultBodyStability { level, feature }, attr.span));
} else {
unreachable!("Unknown stability attribute {meta_name}");
}
}
(None, _, _) => {
@ -542,7 +565,7 @@ where
}
}
(stab, const_stab)
(stab, const_stab, body_stab)
}
pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> {

View File

@ -520,6 +520,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// Gives raw access to the `Allocation`, without bounds or alignment checks.
/// The caller is responsible for calling the access hooks!
///
/// You almost certainly want to use `get_ptr_alloc`/`get_ptr_alloc_mut` instead.
fn get_alloc_raw(
&self,
id: AllocId,
@ -589,6 +591,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Ok(&self.get_alloc_raw(id)?.extra)
}
/// Return the `mutability` field of the given allocation.
pub fn get_alloc_mutability<'a>(&'a self, id: AllocId) -> InterpResult<'tcx, Mutability> {
Ok(self.get_alloc_raw(id)?.mutability)
}
/// Gives raw mutable access to the `Allocation`, without bounds or alignment checks.
/// The caller is responsible for calling the access hooks!
///

View File

@ -772,7 +772,7 @@ impl SyntaxExtension {
)
})
.unwrap_or_else(|| (None, helper_attrs));
let (stability, const_stability) = attr::find_stability(&sess, attrs, span);
let (stability, const_stability, body_stability) = attr::find_stability(&sess, attrs, span);
if let Some((_, sp)) = const_stability {
sess.parse_sess
.span_diagnostic
@ -784,6 +784,17 @@ impl SyntaxExtension {
)
.emit();
}
if let Some((_, sp)) = body_stability {
sess.parse_sess
.span_diagnostic
.struct_span_err(sp, "macros cannot have body stability attributes")
.span_label(sp, "invalid body stability attribute")
.span_label(
sess.source_map().guess_head_span(span),
"body stability attribute affects this macro",
)
.emit();
}
SyntaxExtension {
kind,

View File

@ -499,6 +499,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
),
ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
ungated!(
rustc_default_body_unstable, Normal,
template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk
),
gated!(
allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk,
"allow_internal_unstable side-steps feature gating and stability checks",

View File

@ -207,6 +207,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
def_ident_span => { table }
lookup_stability => { table }
lookup_const_stability => { table }
lookup_default_body_stability => { table }
lookup_deprecation_entry => { table }
visibility => { table }
unused_generic_params => { table }

View File

@ -1029,6 +1029,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
if should_encode_stability(def_kind) {
self.encode_stability(def_id);
self.encode_const_stability(def_id);
self.encode_default_body_stability(def_id);
self.encode_deprecation(def_id);
}
if should_encode_variances(def_kind) {
@ -1385,6 +1386,18 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}
}
fn encode_default_body_stability(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_default_body_stability({:?})", def_id);
// The query lookup can take a measurable amount of time in crates with many items. Check if
// the stability attributes are even enabled before using their queries.
if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
if let Some(stab) = self.tcx.lookup_default_body_stability(def_id) {
record!(self.tables.lookup_default_body_stability[def_id] <- stab)
}
}
}
fn encode_deprecation(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_deprecation({:?})", def_id);
if let Some(depr) = self.tcx.lookup_deprecation(def_id) {

View File

@ -343,6 +343,7 @@ define_tables! {
def_ident_span: Table<DefIndex, LazyValue<Span>>,
lookup_stability: Table<DefIndex, LazyValue<attr::Stability>>,
lookup_const_stability: Table<DefIndex, LazyValue<attr::ConstStability>>,
lookup_default_body_stability: Table<DefIndex, LazyValue<attr::DefaultBodyStability>>,
lookup_deprecation_entry: Table<DefIndex, LazyValue<attr::Deprecation>>,
// As an optimization, a missing entry indicates an empty `&[]`.
explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>,

View File

@ -5,7 +5,7 @@ pub use self::StabilityLevel::*;
use crate::ty::{self, DefIdTree, TyCtxt};
use rustc_ast::NodeId;
use rustc_attr::{self as attr, ConstStability, Deprecation, Stability};
use rustc_attr::{self as attr, ConstStability, DefaultBodyStability, Deprecation, Stability};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, Diagnostic};
use rustc_feature::GateIssue;
@ -61,6 +61,7 @@ pub struct Index {
/// are filled by the annotator.
pub stab_map: FxHashMap<LocalDefId, Stability>,
pub const_stab_map: FxHashMap<LocalDefId, ConstStability>,
pub default_body_stab_map: FxHashMap<LocalDefId, DefaultBodyStability>,
pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>,
/// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]`
/// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute
@ -86,6 +87,10 @@ impl Index {
self.const_stab_map.get(&def_id).copied()
}
pub fn local_default_body_stability(&self, def_id: LocalDefId) -> Option<DefaultBodyStability> {
self.default_body_stab_map.get(&def_id).copied()
}
pub fn local_deprecation_entry(&self, def_id: LocalDefId) -> Option<DeprecationEntry> {
self.depr_map.get(&def_id).cloned()
}
@ -416,6 +421,12 @@ impl<'tcx> TyCtxt<'tcx> {
return EvalResult::Allow;
}
// Only the cross-crate scenario matters when checking unstable APIs
let cross_crate = !def_id.is_local();
if !cross_crate {
return EvalResult::Allow;
}
let stability = self.lookup_stability(def_id);
debug!(
"stability: \
@ -423,12 +434,6 @@ impl<'tcx> TyCtxt<'tcx> {
def_id, span, stability
);
// Only the cross-crate scenario matters when checking unstable APIs
let cross_crate = !def_id.is_local();
if !cross_crate {
return EvalResult::Allow;
}
// Issue #38412: private items lack stability markers.
if skip_stability_check_due_to_privacy(self, def_id) {
return EvalResult::Allow;
@ -492,6 +497,62 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
/// Evaluates the default-impl stability of an item.
///
/// Returns `EvalResult::Allow` if the item's default implementation is stable, or unstable but the corresponding
/// `#![feature]` has been provided. Returns `EvalResult::Deny` which describes the offending
/// unstable feature otherwise.
pub fn eval_default_body_stability(self, def_id: DefId, span: Span) -> EvalResult {
let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some();
if !is_staged_api {
return EvalResult::Allow;
}
// Only the cross-crate scenario matters when checking unstable APIs
let cross_crate = !def_id.is_local();
if !cross_crate {
return EvalResult::Allow;
}
let stability = self.lookup_default_body_stability(def_id);
debug!(
"body stability: inspecting def_id={def_id:?} span={span:?} of stability={stability:?}"
);
// Issue #38412: private items lack stability markers.
if skip_stability_check_due_to_privacy(self, def_id) {
return EvalResult::Allow;
}
match stability {
Some(DefaultBodyStability {
level: attr::Unstable { reason, issue, is_soft, .. },
feature,
}) => {
if span.allows_unstable(feature) {
debug!("body stability: skipping span={:?} since it is internal", span);
return EvalResult::Allow;
}
if self.features().active(feature) {
return EvalResult::Allow;
}
EvalResult::Deny {
feature,
reason: reason.to_opt_reason(),
issue,
suggestion: None,
is_soft,
}
}
Some(_) => {
// Stable APIs are always ok to call
EvalResult::Allow
}
None => EvalResult::Unmarked,
}
}
/// Checks if an item is stable or error out.
///
/// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not

View File

@ -80,6 +80,8 @@ macro_rules! make_mir_visitor {
self.super_body(body);
}
extra_body_methods!($($mutability)?);
fn visit_basic_block_data(
&mut self,
block: BasicBlock,
@ -287,63 +289,7 @@ macro_rules! make_mir_visitor {
&mut self,
body: &$($mutability)? Body<'tcx>,
) {
let span = body.span;
if let Some(gen) = &$($mutability)? body.generator {
if let Some(yield_ty) = $(& $mutability)? gen.yield_ty {
self.visit_ty(
yield_ty,
TyContext::YieldTy(SourceInfo::outermost(span))
);
}
}
// for best performance, we want to use an iterator rather
// than a for-loop, to avoid calling `body::Body::invalidate` for
// each basic block.
#[allow(unused_macro_rules)]
macro_rules! basic_blocks {
(mut) => (body.basic_blocks_mut().iter_enumerated_mut());
() => (body.basic_blocks().iter_enumerated());
}
for (bb, data) in basic_blocks!($($mutability)?) {
self.visit_basic_block_data(bb, data);
}
for scope in &$($mutability)? body.source_scopes {
self.visit_source_scope_data(scope);
}
self.visit_ty(
$(& $mutability)? body.return_ty(),
TyContext::ReturnTy(SourceInfo::outermost(body.span))
);
for local in body.local_decls.indices() {
self.visit_local_decl(local, & $($mutability)? body.local_decls[local]);
}
#[allow(unused_macro_rules)]
macro_rules! type_annotations {
(mut) => (body.user_type_annotations.iter_enumerated_mut());
() => (body.user_type_annotations.iter_enumerated());
}
for (index, annotation) in type_annotations!($($mutability)?) {
self.visit_user_type_annotation(
index, annotation
);
}
for var_debug_info in &$($mutability)? body.var_debug_info {
self.visit_var_debug_info(var_debug_info);
}
self.visit_span($(& $mutability)? body.span);
for const_ in &$($mutability)? body.required_consts {
let location = START_BLOCK.start_location();
self.visit_constant(const_, location);
}
super_body!(self, body, $($mutability, true)?);
}
fn super_basic_block_data(&mut self,
@ -982,12 +928,7 @@ macro_rules! make_mir_visitor {
body: &$($mutability)? Body<'tcx>,
location: Location
) {
#[allow(unused_macro_rules)]
macro_rules! basic_blocks {
(mut) => (body.basic_blocks_mut());
() => (body.basic_blocks());
}
let basic_block = & $($mutability)? basic_blocks!($($mutability)?)[location.block];
let basic_block = & $($mutability)? basic_blocks!(body, $($mutability, true)?)[location.block];
if basic_block.statements.len() == location.statement_index {
if let Some(ref $($mutability)? terminator) = basic_block.terminator {
self.visit_terminator(terminator, location)
@ -1002,6 +943,94 @@ macro_rules! make_mir_visitor {
}
}
macro_rules! basic_blocks {
($body:ident, mut, true) => {
$body.basic_blocks.as_mut()
};
($body:ident, mut, false) => {
$body.basic_blocks.as_mut_preserves_cfg()
};
($body:ident,) => {
$body.basic_blocks()
};
}
macro_rules! basic_blocks_iter {
($body:ident, mut, $invalidate:tt) => {
basic_blocks!($body, mut, $invalidate).iter_enumerated_mut()
};
($body:ident,) => {
basic_blocks!($body,).iter_enumerated()
};
}
macro_rules! extra_body_methods {
(mut) => {
fn visit_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) {
self.super_body_preserves_cfg(body);
}
fn super_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) {
super_body!(self, body, mut, false);
}
};
() => {};
}
macro_rules! super_body {
($self:ident, $body:ident, $($mutability:ident, $invalidate:tt)?) => {
let span = $body.span;
if let Some(gen) = &$($mutability)? $body.generator {
if let Some(yield_ty) = $(& $mutability)? gen.yield_ty {
$self.visit_ty(
yield_ty,
TyContext::YieldTy(SourceInfo::outermost(span))
);
}
}
for (bb, data) in basic_blocks_iter!($body, $($mutability, $invalidate)?) {
$self.visit_basic_block_data(bb, data);
}
for scope in &$($mutability)? $body.source_scopes {
$self.visit_source_scope_data(scope);
}
$self.visit_ty(
$(& $mutability)? $body.return_ty(),
TyContext::ReturnTy(SourceInfo::outermost($body.span))
);
for local in $body.local_decls.indices() {
$self.visit_local_decl(local, & $($mutability)? $body.local_decls[local]);
}
#[allow(unused_macro_rules)]
macro_rules! type_annotations {
(mut) => ($body.user_type_annotations.iter_enumerated_mut());
() => ($body.user_type_annotations.iter_enumerated());
}
for (index, annotation) in type_annotations!($($mutability)?) {
$self.visit_user_type_annotation(
index, annotation
);
}
for var_debug_info in &$($mutability)? $body.var_debug_info {
$self.visit_var_debug_info(var_debug_info);
}
$self.visit_span($(& $mutability)? $body.span);
for const_ in &$($mutability)? $body.required_consts {
let location = START_BLOCK.start_location();
$self.visit_constant(const_, location);
}
}
}
macro_rules! visit_place_fns {
(mut) => {
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;

View File

@ -1094,6 +1094,11 @@ rustc_queries! {
separate_provide_extern
}
query lookup_default_body_stability(def_id: DefId) -> Option<attr::DefaultBodyStability> {
desc { |tcx| "looking up default body stability of `{}`", tcx.def_path_str(def_id) }
separate_provide_extern
}
query should_inherit_track_caller(def_id: DefId) -> bool {
desc { |tcx| "computing should_inherit_track_caller of `{}`", tcx.def_path_str(def_id) }
}
@ -1951,6 +1956,14 @@ rustc_queries! {
}
}
query is_impossible_method(key: (DefId, DefId)) -> bool {
desc { |tcx|
"checking if {} is impossible to call within {}",
tcx.def_path_str(key.1),
tcx.def_path_str(key.0),
}
}
query method_autoderef_steps(
goal: CanonicalTyGoal<'tcx>
) -> MethodAutoderefStepsResult<'tcx> {

View File

@ -64,6 +64,7 @@ trivially_parameterized_over_tcx! {
rustc_ast::Attribute,
rustc_ast::MacArgs,
rustc_attr::ConstStability,
rustc_attr::DefaultBodyStability,
rustc_attr::Deprecation,
rustc_attr::Stability,
rustc_hir::Constness,

View File

@ -849,22 +849,22 @@ fn non_exhaustive_match<'p, 'tcx>(
));
}
[.., prev, last] if prev.span.eq_ctxt(last.span) => {
if let Ok(snippet) = sm.span_to_snippet(prev.span.between(last.span)) {
let comma = if matches!(last.body.kind, hir::ExprKind::Block(..))
&& last.span.eq_ctxt(last.body.span)
{
""
} else {
","
};
let comma = if matches!(last.body.kind, hir::ExprKind::Block(..))
&& last.span.eq_ctxt(last.body.span)
{
""
} else {
","
};
let spacing = if sm.is_multiline(prev.span.between(last.span)) {
sm.indentation_before(last.span).map(|indent| format!("\n{indent}"))
} else {
Some(" ".to_string())
};
if let Some(spacing) = spacing {
suggestion = Some((
last.span.shrink_to_hi(),
format!(
"{}{}{} => todo!()",
comma,
snippet.strip_prefix(',').unwrap_or(&snippet),
pattern
),
format!("{}{}{} => todo!()", comma, spacing, pattern),
));
}
}

View File

@ -33,7 +33,7 @@ pub struct DeleteNonCodegenStatements<'tcx> {
impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let mut delete = DeleteNonCodegenStatements { tcx };
delete.visit_body(body);
delete.visit_body_preserves_cfg(body);
body.user_type_annotations.raw.clear();
for decl in &mut body.local_decls {

View File

@ -951,7 +951,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
}
fn visit_body(&mut self, body: &mut Body<'tcx>) {
for (bb, data) in body.basic_blocks_mut().iter_enumerated_mut() {
for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
self.visit_basic_block_data(bb, data);
}
}

View File

@ -90,7 +90,7 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let patch = MirPatch::new(body);
let mut checker = DerefChecker { tcx, patcher: patch, local_decls: body.local_decls.clone() };
for (bb, data) in body.basic_blocks_mut().iter_enumerated_mut() {
for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
checker.visit_basic_block_data(bb, data);
}

View File

@ -116,7 +116,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs {
ElaborateBoxDerefVisitor { tcx, unique_did, nonnull_did, local_decls, patch };
for (block, BasicBlockData { statements, terminator, .. }) in
body.basic_blocks.as_mut().iter_enumerated_mut()
body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut()
{
let mut index = 0;
for statement in statements {

View File

@ -53,10 +53,10 @@ impl<'tcx> MirPass<'tcx> for RenameReturnPlace {
def_id, returned_local
);
RenameToReturnPlace { tcx, to_rename: returned_local }.visit_body(body);
RenameToReturnPlace { tcx, to_rename: returned_local }.visit_body_preserves_cfg(body);
// Clean up the `NOP`s we inserted for statements made useless by our renaming.
for block_data in body.basic_blocks_mut() {
for block_data in body.basic_blocks.as_mut_preserves_cfg() {
block_data.statements.retain(|stmt| stmt.kind != mir::StatementKind::Nop);
}

View File

@ -19,7 +19,7 @@ impl<'tcx> MirPass<'tcx> for RevealAll {
}
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
RevealAllVisitor { tcx, param_env }.visit_body(body);
RevealAllVisitor { tcx, param_env }.visit_body_preserves_cfg(body);
}
}

View File

@ -412,7 +412,7 @@ pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) {
if map.iter().any(Option::is_none) {
// Update references to all vars and tmps now
let mut updater = LocalUpdater { map, tcx };
updater.visit_body(body);
updater.visit_body_preserves_cfg(body);
body.local_decls.shrink_to_fit();
}
@ -548,7 +548,7 @@ fn remove_unused_definitions(used_locals: &mut UsedLocals, body: &mut Body<'_>)
while modified {
modified = false;
for data in body.basic_blocks_mut() {
for data in body.basic_blocks.as_mut_preserves_cfg() {
// Remove unnecessary StorageLive and StorageDead annotations.
data.statements.retain(|statement| {
let keep = match &statement.kind {

View File

@ -29,11 +29,16 @@ impl<'tcx> LibFeatureCollector<'tcx> {
}
fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option<Symbol>, Span)> {
let stab_attrs =
[sym::stable, sym::unstable, sym::rustc_const_stable, sym::rustc_const_unstable];
let stab_attrs = [
sym::stable,
sym::unstable,
sym::rustc_const_stable,
sym::rustc_const_unstable,
sym::rustc_default_body_unstable,
];
// Find a stability attribute: one of #[stable(…)], #[unstable(…)],
// #[rustc_const_stable(…)], or #[rustc_const_unstable(…)].
// #[rustc_const_stable(…)], #[rustc_const_unstable(…)] or #[rustc_default_body_unstable].
if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.has_name(**stab_attr)) {
let meta_kind = attr.meta_kind();
if let Some(MetaItemKind::List(ref metas)) = meta_kind {
@ -53,8 +58,12 @@ impl<'tcx> LibFeatureCollector<'tcx> {
// This additional check for stability is to make sure we
// don't emit additional, irrelevant errors for malformed
// attributes.
let is_unstable =
matches!(*stab_attr, sym::unstable | sym::rustc_const_unstable);
let is_unstable = matches!(
*stab_attr,
sym::unstable
| sym::rustc_const_unstable
| sym::rustc_default_body_unstable
);
if since.is_some() || is_unstable {
return Some((feature, since, attr.span));
}

View File

@ -1,11 +1,12 @@
//! Checks validity of naked functions.
use rustc_ast::{Attribute, InlineAsmOptions};
use rustc_ast::InlineAsmOptions;
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{FnKind, Visitor};
use rustc_hir::{ExprKind, HirId, InlineAsmOperand, StmtKind};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{ExprKind, InlineAsmOperand, StmtKind};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
@ -13,71 +14,58 @@ use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckNakedFunctions { tcx });
}
pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers { check_mod_naked_functions, ..*providers };
}
struct CheckNakedFunctions<'tcx> {
tcx: TyCtxt<'tcx>,
}
impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> {
fn visit_fn(
&mut self,
fk: FnKind<'_>,
_fd: &'tcx hir::FnDecl<'tcx>,
body_id: hir::BodyId,
span: Span,
hir_id: HirId,
) {
let ident_span;
let fn_header;
match fk {
FnKind::Closure => {
// Closures with a naked attribute are rejected during attribute
// check. Don't validate them any further.
return;
}
FnKind::ItemFn(ident, _, ref header, ..) => {
ident_span = ident.span;
fn_header = header;
}
FnKind::Method(ident, ref sig, ..) => {
ident_span = ident.span;
fn_header = &sig.header;
}
fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
let items = tcx.hir_module_items(module_def_id);
for def_id in items.definitions() {
if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) {
continue;
}
let attrs = self.tcx.hir().attrs(hir_id);
let naked = attrs.iter().any(|attr| attr.has_name(sym::naked));
if naked {
let body = self.tcx.hir().body(body_id);
check_abi(self.tcx, hir_id, fn_header.abi, ident_span);
check_no_patterns(self.tcx, body.params);
check_no_parameters_use(self.tcx, body);
check_asm(self.tcx, body, span);
check_inline(self.tcx, attrs);
let naked = tcx.has_attr(def_id.to_def_id(), sym::naked);
if !naked {
continue;
}
let (fn_header, body_id) = match tcx.hir().get_by_def_id(def_id) {
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })
| hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)),
..
})
| hir::Node::ImplItem(hir::ImplItem {
kind: hir::ImplItemKind::Fn(sig, body_id),
..
}) => (sig.header, *body_id),
_ => continue,
};
let body = tcx.hir().body(body_id);
check_abi(tcx, def_id, fn_header.abi);
check_no_patterns(tcx, body.params);
check_no_parameters_use(tcx, body);
check_asm(tcx, def_id, body);
check_inline(tcx, def_id);
}
}
/// Check that the function isn't inlined.
fn check_inline(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
for attr in attrs.iter().filter(|attr| attr.has_name(sym::inline)) {
fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let attrs = tcx.get_attrs(def_id.to_def_id(), sym::inline);
for attr in attrs {
tcx.sess.struct_span_err(attr.span, "naked functions cannot be inlined").emit();
}
}
/// Checks that function uses non-Rust ABI.
fn check_abi(tcx: TyCtxt<'_>, hir_id: HirId, abi: Abi, fn_ident_span: Span) {
fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: Abi) {
if abi == Abi::Rust {
tcx.struct_span_lint_hir(UNDEFINED_NAKED_FUNCTION_ABI, hir_id, fn_ident_span, |lint| {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let span = tcx.def_span(def_id);
tcx.struct_span_lint_hir(UNDEFINED_NAKED_FUNCTION_ABI, hir_id, span, |lint| {
lint.build("Rust ABI is unsupported in naked functions").emit();
});
}
@ -141,7 +129,7 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
}
/// Checks that function body contains a single inline assembly block.
fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>, fn_span: Span) {
fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) {
let mut this = CheckInlineAssembly { tcx, items: Vec::new() };
this.visit_body(body);
if let [(ItemKind::Asm | ItemKind::Err, _)] = this.items[..] {
@ -149,7 +137,7 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>, fn_span: Span
} else {
let mut diag = struct_span_err!(
tcx.sess,
fn_span,
tcx.def_span(def_id),
E0787,
"naked functions must contain a single asm block"
);

View File

@ -1,8 +1,9 @@
//! A pass that annotates every item and method with its stability level,
//! propagating default levels lexically from parent to children ast nodes.
use attr::StabilityLevel;
use rustc_attr::{self as attr, ConstStability, Stability, Unstable, UnstableReason};
use rustc_attr::{
self as attr, ConstStability, Stability, StabilityLevel, Unstable, UnstableReason,
};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
@ -161,7 +162,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
return;
}
let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp);
let (stab, const_stab, body_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp);
let mut const_span = None;
let const_stab = const_stab.map(|(const_stab, const_span_node)| {
@ -209,6 +210,13 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
}
}
if let Some((body_stab, _span)) = body_stab {
// FIXME: check that this item can have body stability
self.index.default_body_stab_map.insert(def_id, body_stab);
debug!(?self.index.default_body_stab_map);
}
let stab = stab.map(|(stab, span)| {
// Error if prohibited, or can't inherit anything from a container.
if kind == AnnotationKind::Prohibited
@ -613,6 +621,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
let mut index = Index {
stab_map: Default::default(),
const_stab_map: Default::default(),
default_body_stab_map: Default::default(),
depr_map: Default::default(),
implications: Default::default(),
};
@ -673,6 +682,9 @@ pub(crate) fn provide(providers: &mut Providers) {
stability_implications: |tcx, _| tcx.stability().implications.clone(),
lookup_stability: |tcx, id| tcx.stability().local_stability(id.expect_local()),
lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id.expect_local()),
lookup_default_body_stability: |tcx, id| {
tcx.stability().local_default_body_stability(id.expect_local())
},
lookup_deprecation_entry: |tcx, id| {
tcx.stability().local_deprecation_entry(id.expect_local())
},
@ -723,7 +735,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
let features = self.tcx.features();
if features.staged_api {
let attrs = self.tcx.hir().attrs(item.hir_id());
let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item.span);
let (stab, const_stab, _) =
attr::find_stability(&self.tcx.sess, attrs, item.span);
// If this impl block has an #[unstable] attribute, give an
// error if all involved types and traits are stable, because

View File

@ -2544,12 +2544,15 @@ fn show_candidates(
Applicability::MaybeIncorrect,
);
if let [first, .., last] = &path[..] {
err.span_suggestion_verbose(
first.ident.span.until(last.ident.span),
&format!("if you import `{}`, refer to it directly", last.ident),
"",
Applicability::Unspecified,
);
let sp = first.ident.span.until(last.ident.span);
if sp.can_be_used_for_suggestions() {
err.span_suggestion_verbose(
sp,
&format!("if you import `{}`, refer to it directly", last.ident),
"",
Applicability::Unspecified,
);
}
}
} else {
msg.push(':');

View File

@ -1218,6 +1218,7 @@ symbols! {
rustc_conversion_suggestion,
rustc_deallocator,
rustc_def_path,
rustc_default_body_unstable,
rustc_diagnostic_item,
rustc_diagnostic_macros,
rustc_dirty,

View File

@ -1315,6 +1315,13 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
error: &MismatchedProjectionTypes<'tcx>,
);
fn maybe_detailed_projection_msg(
&self,
pred: ty::ProjectionPredicate<'tcx>,
normalized_ty: ty::Term<'tcx>,
expected_ty: ty::Term<'tcx>,
) -> Option<String>;
fn fuzzy_match_tys(
&self,
a: Ty<'tcx>,
@ -1542,23 +1549,19 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
normalized_ty,
data.term,
) {
values = Some(infer::ValuePairs::Terms(ExpectedFound::new(
is_normalized_ty_expected,
normalized_ty,
data.term,
)));
values = Some((data, is_normalized_ty_expected, normalized_ty, data.term));
err_buf = error;
err = &err_buf;
}
}
let mut diag = struct_span_err!(
self.tcx.sess,
obligation.cause.span,
E0271,
"type mismatch resolving `{}`",
predicate
);
let msg = values
.and_then(|(predicate, _, normalized_ty, expected_ty)| {
self.maybe_detailed_projection_msg(predicate, normalized_ty, expected_ty)
})
.unwrap_or_else(|| format!("type mismatch resolving `{}`", predicate));
let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
let secondary_span = match predicate.kind().skip_binder() {
ty::PredicateKind::Projection(proj) => self
.tcx
@ -1596,7 +1599,13 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
&mut diag,
&obligation.cause,
secondary_span,
values,
values.map(|(_, is_normalized_ty_expected, normalized_ty, term)| {
infer::ValuePairs::Terms(ExpectedFound::new(
is_normalized_ty_expected,
normalized_ty,
term,
))
}),
err,
true,
false,
@ -1606,6 +1615,33 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
});
}
fn maybe_detailed_projection_msg(
&self,
pred: ty::ProjectionPredicate<'tcx>,
normalized_ty: ty::Term<'tcx>,
expected_ty: ty::Term<'tcx>,
) -> Option<String> {
let trait_def_id = pred.projection_ty.trait_def_id(self.tcx);
let self_ty = pred.projection_ty.self_ty();
if Some(pred.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output() {
Some(format!(
"expected `{self_ty}` to be a {fn_kind} that returns `{expected_ty}`, but it returns `{normalized_ty}`",
fn_kind = self_ty.prefix_string(self.tcx)
))
} else if Some(trait_def_id) == self.tcx.lang_items().future_trait() {
Some(format!(
"expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it resolves to `{normalized_ty}`"
))
} else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {
Some(format!(
"expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it yields `{normalized_ty}`"
))
} else {
None
}
}
fn fuzzy_match_tys(
&self,
mut a: Ty<'tcx>,

View File

@ -34,7 +34,10 @@ use rustc_infer::traits::TraitEngineExt as _;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry};
use rustc_middle::ty::{
self, DefIdTree, GenericParamDefKind, Subst, ToPredicate, Ty, TyCtxt, TypeSuperVisitable,
VtblEntry,
};
use rustc_span::{sym, Span};
use smallvec::SmallVec;
@ -503,6 +506,77 @@ fn subst_and_check_impossible_predicates<'tcx>(
result
}
/// Checks whether a trait's method is impossible to call on a given impl.
///
/// This only considers predicates that reference the impl's generics, and not
/// those that reference the method's generics.
fn is_impossible_method<'tcx>(
tcx: TyCtxt<'tcx>,
(impl_def_id, trait_item_def_id): (DefId, DefId),
) -> bool {
struct ReferencesOnlyParentGenerics<'tcx> {
tcx: TyCtxt<'tcx>,
generics: &'tcx ty::Generics,
trait_item_def_id: DefId,
}
impl<'tcx> ty::TypeVisitor<'tcx> for ReferencesOnlyParentGenerics<'tcx> {
type BreakTy = ();
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
// If this is a parameter from the trait item's own generics, then bail
if let ty::Param(param) = t.kind()
&& let param_def_id = self.generics.type_param(param, self.tcx).def_id
&& self.tcx.parent(param_def_id) == self.trait_item_def_id
{
return ControlFlow::BREAK;
}
t.super_visit_with(self)
}
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::ReEarlyBound(param) = r.kind()
&& let param_def_id = self.generics.region_param(&param, self.tcx).def_id
&& self.tcx.parent(param_def_id) == self.trait_item_def_id
{
return ControlFlow::BREAK;
}
r.super_visit_with(self)
}
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::ConstKind::Param(param) = ct.kind()
&& let param_def_id = self.generics.const_param(&param, self.tcx).def_id
&& self.tcx.parent(param_def_id) == self.trait_item_def_id
{
return ControlFlow::BREAK;
}
ct.super_visit_with(self)
}
}
let generics = tcx.generics_of(trait_item_def_id);
let predicates = tcx.predicates_of(trait_item_def_id);
let impl_trait_ref =
tcx.impl_trait_ref(impl_def_id).expect("expected impl to correspond to trait");
let param_env = tcx.param_env(impl_def_id);
let mut visitor = ReferencesOnlyParentGenerics { tcx, generics, trait_item_def_id };
let predicates_for_trait = predicates.predicates.iter().filter_map(|(pred, span)| {
if pred.visit_with(&mut visitor).is_continue() {
Some(Obligation::new(
ObligationCause::dummy_with_span(*span),
param_env,
ty::EarlyBinder(*pred).subst(tcx, impl_trait_ref.substs),
))
} else {
None
}
});
tcx.infer_ctxt().ignoring_regions().enter(|ref infcx| {
let mut fulfill_ctxt = <dyn TraitEngine<'_>>::new(tcx);
fulfill_ctxt.register_predicate_obligations(infcx, predicates_for_trait);
!fulfill_ctxt.select_all_or_error(infcx).is_empty()
})
}
#[derive(Clone, Debug)]
enum VtblSegment<'tcx> {
MetadataDSA,
@ -883,6 +957,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
vtable_entries,
vtable_trait_upcasting_coercion_new_vptr_slot,
subst_and_check_impossible_predicates,
is_impossible_method,
try_unify_abstract_consts: |tcx, param_env_and| {
let (param_env, (a, b)) = param_env_and.into_parts();
const_evaluatable::try_unify_abstract_consts(tcx, (a, b), param_env)

View File

@ -30,3 +30,4 @@ rustc_ty_utils = { path = "../rustc_ty_utils" }
rustc_lint = { path = "../rustc_lint" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_type_ir = { path = "../rustc_type_ir" }
rustc_feature = { path = "../rustc_feature" }

View File

@ -18,6 +18,7 @@ use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::stability::EvalResult;
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::util::{Discr, IntTypeExt};
@ -32,7 +33,6 @@ use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCtxt};
use rustc_ty_utils::representability::{self, Representability};
use std::iter;
use std::ops::ControlFlow;
pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
@ -1104,12 +1104,28 @@ fn check_impl_items_against_trait<'tcx>(
missing_items.push(tcx.associated_item(trait_item_id));
}
if let Some(required_items) = &must_implement_one_of {
// true if this item is specifically implemented in this impl
let is_implemented_here = ancestors
.leaf_def(tcx, trait_item_id)
.map_or(false, |node_item| !node_item.defining_node.is_from_trait());
// true if this item is specifically implemented in this impl
let is_implemented_here = ancestors
.leaf_def(tcx, trait_item_id)
.map_or(false, |node_item| !node_item.defining_node.is_from_trait());
if !is_implemented_here {
match tcx.eval_default_body_stability(trait_item_id, full_impl_span) {
EvalResult::Deny { feature, reason, issue, .. } => default_body_is_unstable(
tcx,
full_impl_span,
trait_item_id,
feature,
reason,
issue,
),
// Unmarked default bodies are considered stable (at least for now).
EvalResult::Allow | EvalResult::Unmarked => {}
}
}
if let Some(required_items) = &must_implement_one_of {
if is_implemented_here {
let trait_item = tcx.associated_item(trait_item_id);
if required_items.contains(&trait_item.ident(tcx)) {
@ -1494,76 +1510,109 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
}
}
let mut disr_vals: Vec<Discr<'tcx>> = Vec::with_capacity(vs.len());
// This tracks the previous variant span (in the loop) incase we need it for diagnostics
let mut prev_variant_span: Span = DUMMY_SP;
for ((_, discr), v) in iter::zip(def.discriminants(tcx), vs) {
// Check for duplicate discriminant values
if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) {
let variant_did = def.variant(VariantIdx::new(i)).def_id;
let variant_i_hir_id = tcx.hir().local_def_id_to_hir_id(variant_did.expect_local());
let variant_i = tcx.hir().expect_variant(variant_i_hir_id);
let i_span = match variant_i.disr_expr {
Some(ref expr) => tcx.hir().span(expr.hir_id),
None => tcx.def_span(variant_did),
};
let span = match v.disr_expr {
Some(ref expr) => tcx.hir().span(expr.hir_id),
None => v.span,
};
let display_discr = format_discriminant_overflow(tcx, v, discr);
let display_discr_i = format_discriminant_overflow(tcx, variant_i, disr_vals[i]);
let no_disr = v.disr_expr.is_none();
let mut err = struct_span_err!(
tcx.sess,
sp,
E0081,
"discriminant value `{}` assigned more than once",
discr,
);
err.span_label(i_span, format!("first assignment of {display_discr_i}"));
err.span_label(span, format!("second assignment of {display_discr}"));
if no_disr {
err.span_label(
prev_variant_span,
format!(
"assigned discriminant for `{}` was incremented from this discriminant",
v.ident
),
);
}
err.emit();
}
disr_vals.push(discr);
prev_variant_span = v.span;
}
detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp);
check_representable(tcx, sp, def_id);
check_transparent(tcx, sp, def);
}
/// In the case that a discriminant is both a duplicate and an overflowing literal,
/// we insert both the assigned discriminant and the literal it overflowed from into the formatted
/// output. Otherwise we format the discriminant normally.
fn format_discriminant_overflow<'tcx>(
/// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal
fn detect_discriminant_duplicate<'tcx>(
tcx: TyCtxt<'tcx>,
variant: &hir::Variant<'_>,
dis: Discr<'tcx>,
) -> String {
if let Some(expr) = &variant.disr_expr {
let body = &tcx.hir().body(expr.body).value;
if let hir::ExprKind::Lit(lit) = &body.kind
&& let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
&& dis.val != *lit_value
{
return format!("`{dis}` (overflowed from `{lit_value}`)");
}
}
mut discrs: Vec<(VariantIdx, Discr<'tcx>)>,
vs: &'tcx [hir::Variant<'tcx>],
self_span: Span,
) {
// Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate.
// Here `idx` refers to the order of which the discriminant appears, and its index in `vs`
let report = |dis: Discr<'tcx>,
idx: usize,
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>| {
let var = &vs[idx]; // HIR for the duplicate discriminant
let (span, display_discr) = match var.disr_expr {
Some(ref expr) => {
// In the case the discriminant is both a duplicate and overflowed, let the user know
if let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind
&& let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
&& *lit_value != dis.val
{
(tcx.hir().span(expr.hir_id), format!("`{dis}` (overflowed from `{lit_value}`)"))
// Otherwise, format the value as-is
} else {
(tcx.hir().span(expr.hir_id), format!("`{dis}`"))
}
}
None => {
// At this point we know this discriminant is a duplicate, and was not explicitly
// assigned by the user. Here we iterate backwards to fetch the HIR for the last
// explictly assigned discriminant, and letting the user know that this was the
// increment startpoint, and how many steps from there leading to the duplicate
if let Some((n, hir::Variant { span, ident, .. })) =
vs[..idx].iter().rev().enumerate().find(|v| v.1.disr_expr.is_some())
{
let ve_ident = var.ident;
let n = n + 1;
let sp = if n > 1 { "variants" } else { "variant" };
format!("`{dis}`")
err.span_label(
*span,
format!("discriminant for `{ve_ident}` incremented from this startpoint (`{ident}` + {n} {sp} later => `{ve_ident}` = {dis})"),
);
}
(vs[idx].span, format!("`{dis}`"))
}
};
err.span_label(span, format!("{display_discr} assigned here"));
};
// Here we loop through the discriminants, comparing each discriminant to another.
// When a duplicate is detected, we instatiate an error and point to both
// initial and duplicate value. The duplicate discriminant is then discarded by swapping
// it with the last element and decrementing the `vec.len` (which is why we have to evaluate
// `discrs.len()` anew every iteration, and why this could be tricky to do in a functional
// style as we are mutating `discrs` on the fly).
let mut i = 0;
while i < discrs.len() {
let hir_var_i_idx = discrs[i].0.index();
let mut error: Option<DiagnosticBuilder<'_, _>> = None;
let mut o = i + 1;
while o < discrs.len() {
let hir_var_o_idx = discrs[o].0.index();
if discrs[i].1.val == discrs[o].1.val {
let err = error.get_or_insert_with(|| {
let mut ret = struct_span_err!(
tcx.sess,
self_span,
E0081,
"discriminant value `{}` assigned more than once",
discrs[i].1,
);
report(discrs[i].1, hir_var_i_idx, &mut ret);
ret
});
report(discrs[o].1, hir_var_o_idx, err);
// Safe to unwrap here, as we wouldn't reach this point if `discrs` was empty
discrs[o] = *discrs.last().unwrap();
discrs.pop();
} else {
o += 1;
}
}
if let Some(mut e) = error {
e.emit();
}
i += 1;
}
}
pub(super) fn check_type_params_are_used<'tcx>(

View File

@ -1589,11 +1589,11 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
) {
let hir::ExprKind::Loop(_, _, _, loop_span) = expr.kind else { return;};
let mut span: MultiSpan = vec![loop_span].into();
span.push_span_label(loop_span, "this might have zero elements to iterate on".to_string());
span.push_span_label(loop_span, "this might have zero elements to iterate on");
for ret_expr in ret_exprs {
span.push_span_label(
ret_expr.span,
"if the loop doesn't execute, this value would never get returned".to_string(),
"if the loop doesn't execute, this value would never get returned",
);
}
err.span_note(

View File

@ -50,7 +50,6 @@ use rustc_span::hygiene::DesugaringKind;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::{Span, Spanned};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, Pos};
use rustc_target::spec::abi::Abi::RustIntrinsic;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::{self, ObligationCauseCode};
@ -2398,37 +2397,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr,
Some(span),
);
} else if let ty::RawPtr(ty_and_mut) = expr_t.kind()
&& let ty::Adt(adt_def, _) = ty_and_mut.ty.kind()
&& let ExprKind::Field(base_expr, _) = expr.kind
&& adt_def.variants().len() == 1
&& adt_def
.variants()
.iter()
.next()
.unwrap()
.fields
.iter()
.any(|f| f.ident(self.tcx) == field)
{
err.multipart_suggestion(
"to access the field, dereference first",
vec![
(base_expr.span.shrink_to_lo(), "(*".to_string()),
(base_expr.span.shrink_to_hi(), ")".to_string()),
],
Applicability::MaybeIncorrect,
);
} else {
let mut found = false;
if let ty::RawPtr(ty_and_mut) = expr_t.kind()
&& let ty::Adt(adt_def, _) = ty_and_mut.ty.kind()
{
if adt_def.variants().len() == 1
&& adt_def
.variants()
.iter()
.next()
.unwrap()
.fields
.iter()
.any(|f| f.ident(self.tcx) == field)
{
if let Some(dot_loc) = expr_snippet.rfind('.') {
found = true;
err.span_suggestion(
expr.span.with_hi(expr.span.lo() + BytePos::from_usize(dot_loc)),
"to access the field, dereference first",
format!("(*{})", &expr_snippet[0..dot_loc]),
Applicability::MaybeIncorrect,
);
}
}
}
if !found {
err.help("methods are immutable and cannot be assigned to");
}
err.help("methods are immutable and cannot be assigned to");
}
err.emit();

View File

@ -112,7 +112,6 @@ use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
use rustc_index::bit_set::BitSet;
use rustc_index::vec::Idx;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
@ -122,13 +121,14 @@ use rustc_session::parse::feature_err;
use rustc_session::Session;
use rustc_span::source_map::DUMMY_SP;
use rustc_span::symbol::{kw, Ident};
use rustc_span::{self, BytePos, Span};
use rustc_span::{self, BytePos, Span, Symbol};
use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
use std::cell::RefCell;
use std::num::NonZeroU32;
use crate::require_c_abi_if_c_variadic;
use crate::util::common::indenter;
@ -662,6 +662,37 @@ fn missing_items_must_implement_one_of_err(
err.emit();
}
fn default_body_is_unstable(
tcx: TyCtxt<'_>,
impl_span: Span,
item_did: DefId,
feature: Symbol,
reason: Option<Symbol>,
issue: Option<NonZeroU32>,
) {
let missing_item_name = &tcx.associated_item(item_did).name;
let use_of_unstable_library_feature_note = match reason {
Some(r) => format!("use of unstable library feature '{feature}': {r}"),
None => format!("use of unstable library feature '{feature}'"),
};
let mut err = struct_span_err!(
tcx.sess,
impl_span,
E0046,
"not all trait items implemented, missing: `{missing_item_name}`",
);
err.note(format!("default implementation of `{missing_item_name}` is unstable"));
err.note(use_of_unstable_library_feature_note);
rustc_session::parse::add_feature_diagnostics_for_issue(
&mut err,
&tcx.sess.parse_sess,
feature,
rustc_feature::GateIssue::Library(issue),
);
err.emit();
}
/// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
fn bounds_from_generic_predicates<'tcx>(
tcx: TyCtxt<'tcx>,

View File

@ -318,19 +318,11 @@ impl Duration {
/// assert_eq!(duration.as_secs(), 5);
/// ```
///
/// To determine the total number of seconds represented by the `Duration`,
/// use `as_secs` in combination with [`subsec_nanos`]:
///
/// ```
/// use std::time::Duration;
///
/// let duration = Duration::new(5, 730023852);
///
/// assert_eq!(5.730023852,
/// duration.as_secs() as f64
/// + duration.subsec_nanos() as f64 * 1e-9);
/// ```
/// To determine the total number of seconds represented by the `Duration`
/// including the fractional part, use [`as_secs_f64`] or [`as_secs_f32`]
///
/// [`as_secs_f32`]: Duration::as_secs_f64
/// [`as_secs_f64`]: Duration::as_secs_f32
/// [`subsec_nanos`]: Duration::subsec_nanos
#[stable(feature = "duration", since = "1.3.0")]
#[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]

View File

@ -628,6 +628,10 @@ impl Step for Miri {
cargo.env("MIRI_HOST_SYSROOT", sysroot);
cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
cargo.env("MIRI", miri);
// propagate --bless
if builder.config.cmd.bless() {
cargo.env("MIRI_BLESS", "Gesundheit");
}
cargo.arg("--").args(builder.config.cmd.test_args());

View File

@ -88,8 +88,8 @@ def check_type(ty):
for bound in binding["binding"]["constraint"]:
check_generic_bound(bound)
elif "parenthesized" in args:
for ty in args["parenthesized"]["inputs"]:
check_type(ty)
for input_ty in args["parenthesized"]["inputs"]:
check_type(input_ty)
if args["parenthesized"]["output"]:
check_type(args["parenthesized"]["output"])
if not valid_id(ty["inner"]["id"]):

View File

@ -348,15 +348,13 @@ where
fn make_final_bounds(
&self,
ty_to_bounds: FxHashMap<Type, FxHashSet<GenericBound>>,
ty_to_fn: FxHashMap<Type, (Option<PolyTrait>, Option<Type>)>,
ty_to_fn: FxHashMap<Type, (PolyTrait, Option<Type>)>,
lifetime_to_bounds: FxHashMap<Lifetime, FxHashSet<GenericBound>>,
) -> Vec<WherePredicate> {
ty_to_bounds
.into_iter()
.flat_map(|(ty, mut bounds)| {
if let Some(data) = ty_to_fn.get(&ty) {
let (poly_trait, output) =
(data.0.as_ref().unwrap().clone(), data.1.as_ref().cloned().map(Box::new));
if let Some((ref poly_trait, ref output)) = ty_to_fn.get(&ty) {
let mut new_path = poly_trait.trait_.clone();
let last_segment = new_path.segments.pop().expect("segments were empty");
@ -374,8 +372,9 @@ where
GenericArgs::Parenthesized { inputs, output } => (inputs, output),
};
let output = output.as_ref().cloned().map(Box::new);
if old_output.is_some() && old_output != output {
panic!("Output mismatch for {:?} {:?} {:?}", ty, old_output, data.1);
panic!("Output mismatch for {:?} {:?} {:?}", ty, old_output, output);
}
let new_params = GenericArgs::Parenthesized { inputs: old_input, output };
@ -385,7 +384,10 @@ where
.push(PathSegment { name: last_segment.name, args: new_params });
bounds.insert(GenericBound::TraitBound(
PolyTrait { trait_: new_path, generic_params: poly_trait.generic_params },
PolyTrait {
trait_: new_path,
generic_params: poly_trait.generic_params.clone(),
},
hir::TraitBoundModifier::None,
));
}
@ -471,10 +473,10 @@ where
let mut lifetime_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default();
let mut ty_to_traits: FxHashMap<Type, FxHashSet<Path>> = Default::default();
let mut ty_to_fn: FxHashMap<Type, (Option<PolyTrait>, Option<Type>)> = Default::default();
let mut ty_to_fn: FxHashMap<Type, (PolyTrait, Option<Type>)> = Default::default();
for p in clean_where_predicates {
let (orig_p, p) = (p, p.clean(self.cx));
let (orig_p, p) = (p, clean_predicate(p, self.cx));
if p.is_none() {
continue;
}
@ -535,8 +537,8 @@ where
if is_fn {
ty_to_fn
.entry(ty.clone())
.and_modify(|e| *e = (Some(poly_trait.clone()), e.1.clone()))
.or_insert(((Some(poly_trait.clone())), None));
.and_modify(|e| *e = (poly_trait.clone(), e.1.clone()))
.or_insert(((poly_trait.clone()), None));
ty_to_bounds.entry(ty.clone()).or_default();
} else {
@ -559,7 +561,13 @@ where
.and_modify(|e| {
*e = (e.0.clone(), Some(rhs.ty().unwrap().clone()))
})
.or_insert((None, Some(rhs.ty().unwrap().clone())));
.or_insert((
PolyTrait {
trait_: trait_.clone(),
generic_params: Vec::new(),
},
Some(rhs.ty().unwrap().clone()),
));
continue;
}

View File

@ -145,6 +145,7 @@ pub(crate) fn try_inline_glob(
cx: &mut DocContext<'_>,
res: Res,
visited: &mut FxHashSet<DefId>,
inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
) -> Option<Vec<clean::Item>> {
let did = res.opt_def_id()?;
if did.is_local() {
@ -153,8 +154,17 @@ pub(crate) fn try_inline_glob(
match res {
Res::Def(DefKind::Mod, did) => {
let m = build_module(cx, did, visited);
Some(m.items)
let mut items = build_module_items(cx, did, visited, inlined_names);
items.drain_filter(|item| {
if let Some(name) = item.name {
// If an item with the same type and name already exists,
// it takes priority over the inlined stuff.
!inlined_names.insert((item.type_(), name))
} else {
false
}
});
Some(items)
}
// glob imports on things like enums aren't inlined even for local exports, so just bail
_ => None,
@ -517,6 +527,18 @@ fn build_module(
did: DefId,
visited: &mut FxHashSet<DefId>,
) -> clean::Module {
let items = build_module_items(cx, did, visited, &mut FxHashSet::default());
let span = clean::Span::new(cx.tcx.def_span(did));
clean::Module { items, span }
}
fn build_module_items(
cx: &mut DocContext<'_>,
did: DefId,
visited: &mut FxHashSet<DefId>,
inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
) -> Vec<clean::Item> {
let mut items = Vec::new();
// If we're re-exporting a re-export it may actually re-export something in
@ -526,7 +548,13 @@ fn build_module(
if item.vis.is_public() {
let res = item.res.expect_non_local();
if let Some(def_id) = res.mod_def_id() {
if did == def_id || !visited.insert(def_id) {
// If we're inlining a glob import, it's possible to have
// two distinct modules with the same name. We don't want to
// inline it, or mark any of its contents as visited.
if did == def_id
|| inlined_names.contains(&(ItemType::Module, item.ident.name))
|| !visited.insert(def_id)
{
continue;
}
}
@ -563,8 +591,7 @@ fn build_module(
}
}
let span = clean::Span::new(cx.tcx.def_span(did));
clean::Module { items, span }
items
}
pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String {

View File

@ -71,7 +71,7 @@ impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> {
// priority to the not-imported one, so we should, too.
items.extend(self.items.iter().flat_map(|(item, renamed)| {
// First, lower everything other than imports.
if matches!(item.kind, hir::ItemKind::Use(..)) {
if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
return Vec::new();
}
let v = clean_maybe_renamed_item(cx, item, *renamed);
@ -84,20 +84,13 @@ impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> {
}));
items.extend(self.items.iter().flat_map(|(item, renamed)| {
// Now we actually lower the imports, skipping everything else.
if !matches!(item.kind, hir::ItemKind::Use(..)) {
return Vec::new();
if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind {
let name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
clean_use_statement(item, name, path, hir::UseKind::Glob, cx, &mut inserted)
} else {
// skip everything else
Vec::new()
}
let mut v = clean_maybe_renamed_item(cx, item, *renamed);
v.drain_filter(|item| {
if let Some(name) = item.name {
// If an item with the same type and name already exists,
// it takes priority over the inlined stuff.
!inserted.insert((item.type_(), name))
} else {
false
}
});
v
}));
// determine if we should display the inner contents or
@ -266,66 +259,68 @@ pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option<Life
}
}
impl<'tcx> Clean<'tcx, Option<WherePredicate>> for hir::WherePredicate<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
if !self.in_where_clause() {
return None;
}
Some(match *self {
hir::WherePredicate::BoundPredicate(ref wbp) => {
let bound_params = wbp
.bound_generic_params
.iter()
.map(|param| {
// Higher-ranked params must be lifetimes.
// Higher-ranked lifetimes can't have bounds.
assert_matches!(
param,
hir::GenericParam { kind: hir::GenericParamKind::Lifetime { .. }, .. }
);
Lifetime(param.name.ident().name)
})
.collect();
WherePredicate::BoundPredicate {
ty: clean_ty(wbp.bounded_ty, cx),
bounds: wbp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
bound_params,
}
}
hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate {
lifetime: clean_lifetime(wrp.lifetime, cx),
bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
},
hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
lhs: clean_ty(wrp.lhs_ty, cx),
rhs: clean_ty(wrp.rhs_ty, cx).into(),
},
})
fn clean_where_predicate<'tcx>(
predicate: &hir::WherePredicate<'tcx>,
cx: &mut DocContext<'tcx>,
) -> Option<WherePredicate> {
if !predicate.in_where_clause() {
return None;
}
Some(match *predicate {
hir::WherePredicate::BoundPredicate(ref wbp) => {
let bound_params = wbp
.bound_generic_params
.iter()
.map(|param| {
// Higher-ranked params must be lifetimes.
// Higher-ranked lifetimes can't have bounds.
assert_matches!(
param,
hir::GenericParam { kind: hir::GenericParamKind::Lifetime { .. }, .. }
);
Lifetime(param.name.ident().name)
})
.collect();
WherePredicate::BoundPredicate {
ty: clean_ty(wbp.bounded_ty, cx),
bounds: wbp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
bound_params,
}
}
hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate {
lifetime: clean_lifetime(wrp.lifetime, cx),
bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
},
hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
lhs: clean_ty(wrp.lhs_ty, cx),
rhs: clean_ty(wrp.rhs_ty, cx).into(),
},
})
}
impl<'tcx> Clean<'tcx, Option<WherePredicate>> for ty::Predicate<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
let bound_predicate = self.kind();
match bound_predicate.skip_binder() {
ty::PredicateKind::Trait(pred) => {
clean_poly_trait_predicate(bound_predicate.rebind(pred), cx)
}
ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred),
ty::PredicateKind::TypeOutlives(pred) => clean_type_outlives_predicate(pred, cx),
ty::PredicateKind::Projection(pred) => Some(clean_projection_predicate(pred, cx)),
ty::PredicateKind::ConstEvaluatable(..) => None,
ty::PredicateKind::WellFormed(..) => None,
ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"),
pub(crate) fn clean_predicate<'tcx>(
predicate: ty::Predicate<'tcx>,
cx: &mut DocContext<'tcx>,
) -> Option<WherePredicate> {
let bound_predicate = predicate.kind();
match bound_predicate.skip_binder() {
ty::PredicateKind::Trait(pred) => {
clean_poly_trait_predicate(bound_predicate.rebind(pred), cx)
}
ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred),
ty::PredicateKind::TypeOutlives(pred) => clean_type_outlives_predicate(pred, cx),
ty::PredicateKind::Projection(pred) => Some(clean_projection_predicate(pred, cx)),
ty::PredicateKind::ConstEvaluatable(..) => None,
ty::PredicateKind::WellFormed(..) => None,
ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"),
}
}
@ -601,7 +596,11 @@ impl<'tcx> Clean<'tcx, Generics> for hir::Generics<'tcx> {
let mut generics = Generics {
params,
where_predicates: self.predicates.iter().filter_map(|x| x.clean(cx)).collect(),
where_predicates: self
.predicates
.iter()
.filter_map(|x| clean_where_predicate(x, cx))
.collect(),
};
// Some duplicates are generated for ?Sized bounds between type params and where
@ -702,7 +701,7 @@ fn clean_ty_generics<'tcx>(
if let Some(param_idx) = param_idx {
if let Some(b) = impl_trait.get_mut(&param_idx.into()) {
let p: WherePredicate = p.clean(cx)?;
let p: WherePredicate = clean_predicate(*p, cx)?;
b.extend(
p.get_bounds()
@ -759,7 +758,7 @@ fn clean_ty_generics<'tcx>(
// Now that `cx.impl_trait_bounds` is populated, we can process
// remaining predicates which could contain `impl Trait`.
let mut where_predicates =
where_predicates.into_iter().flat_map(|p| p.clean(cx)).collect::<Vec<_>>();
where_predicates.into_iter().flat_map(|p| clean_predicate(*p, cx)).collect::<Vec<_>>();
// Type parameters have a Sized bound by default unless removed with
// ?Sized. Scan through the predicates and mark any type parameter with
@ -1962,7 +1961,7 @@ fn clean_maybe_renamed_item<'tcx>(
return clean_extern_crate(item, name, orig_name, cx);
}
ItemKind::Use(path, kind) => {
return clean_use_statement(item, name, path, kind, cx);
return clean_use_statement(item, name, path, kind, cx, &mut FxHashSet::default());
}
_ => unreachable!("not yet converted"),
};
@ -2083,6 +2082,7 @@ fn clean_use_statement<'tcx>(
path: &hir::Path<'tcx>,
kind: hir::UseKind,
cx: &mut DocContext<'tcx>,
inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
) -> Vec<Item> {
// We need this comparison because some imports (for std types for example)
// are "inserted" as well but directly by the compiler and they should not be
@ -2148,7 +2148,8 @@ fn clean_use_statement<'tcx>(
let inner = if kind == hir::UseKind::Glob {
if !denied {
let mut visited = FxHashSet::default();
if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited) {
if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited, inlined_names)
{
return items;
}
}

View File

@ -1550,6 +1550,15 @@ fn render_impl(
rendering_params: ImplRenderingParameters,
) {
for trait_item in &t.items {
// Skip over any default trait items that are impossible to call
// (e.g. if it has a `Self: Sized` bound on an unsized type).
if let Some(impl_def_id) = parent.item_id.as_def_id()
&& let Some(trait_item_def_id) = trait_item.item_id.as_def_id()
&& cx.tcx().is_impossible_method((impl_def_id, trait_item_def_id))
{
continue;
}
let n = trait_item.name;
if i.items.iter().any(|m| m.name == n) {
continue;

View File

@ -119,6 +119,16 @@ where
}
}
impl<I, T, U> FromWithTcx<I> for Vec<U>
where
I: IntoIterator<Item = T>,
U: FromWithTcx<T>,
{
fn from_tcx(f: I, tcx: TyCtxt<'_>) -> Vec<U> {
f.into_iter().map(|x| x.into_tcx(tcx)).collect()
}
}
pub(crate) fn from_deprecation(deprecation: rustc_attr::Deprecation) -> Deprecation {
#[rustfmt::skip]
let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation;
@ -130,11 +140,11 @@ impl FromWithTcx<clean::GenericArgs> for GenericArgs {
use clean::GenericArgs::*;
match args {
AngleBracketed { args, bindings } => GenericArgs::AngleBracketed {
args: args.into_vec().into_iter().map(|a| a.into_tcx(tcx)).collect(),
bindings: bindings.into_iter().map(|a| a.into_tcx(tcx)).collect(),
args: args.into_vec().into_tcx(tcx),
bindings: bindings.into_tcx(tcx),
},
Parenthesized { inputs, output } => GenericArgs::Parenthesized {
inputs: inputs.into_vec().into_iter().map(|a| a.into_tcx(tcx)).collect(),
inputs: inputs.into_vec().into_tcx(tcx),
output: output.map(|a| (*a).into_tcx(tcx)),
},
}
@ -145,7 +155,7 @@ impl FromWithTcx<clean::GenericArg> for GenericArg {
fn from_tcx(arg: clean::GenericArg, tcx: TyCtxt<'_>) -> Self {
use clean::GenericArg::*;
match arg {
Lifetime(l) => GenericArg::Lifetime(l.0.to_string()),
Lifetime(l) => GenericArg::Lifetime(convert_lifetime(l)),
Type(t) => GenericArg::Type(t.into_tcx(tcx)),
Const(box c) => GenericArg::Const(c.into_tcx(tcx)),
Infer => GenericArg::Infer,
@ -177,9 +187,7 @@ impl FromWithTcx<clean::TypeBindingKind> for TypeBindingKind {
use clean::TypeBindingKind::*;
match kind {
Equality { term } => TypeBindingKind::Equality(term.into_tcx(tcx)),
Constraint { bounds } => {
TypeBindingKind::Constraint(bounds.into_iter().map(|a| a.into_tcx(tcx)).collect())
}
Constraint { bounds } => TypeBindingKind::Constraint(bounds.into_tcx(tcx)),
}
}
}
@ -244,7 +252,7 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_tcx(tcx)),
MethodItem(m, _) => ItemEnum::Method(from_function_method(m, true, header.unwrap(), tcx)),
TyMethodItem(m) => ItemEnum::Method(from_function_method(m, false, header.unwrap(), tcx)),
ImplItem(i) => ItemEnum::Impl(i.into_tcx(tcx)),
ImplItem(i) => ItemEnum::Impl((*i).into_tcx(tcx)),
StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
ForeignStaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
ForeignTypeItem => ItemEnum::ForeignType,
@ -260,12 +268,12 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
}
TyAssocTypeItem(g, b) => ItemEnum::AssocType {
generics: (*g).into_tcx(tcx),
bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(),
bounds: b.into_tcx(tcx),
default: None,
},
AssocTypeItem(t, b) => ItemEnum::AssocType {
generics: t.generics.into_tcx(tcx),
bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(),
bounds: b.into_tcx(tcx),
default: Some(t.item_type.unwrap_or(t.type_).into_tcx(tcx)),
},
// `convert_item` early returns `None` for stripped items and keywords.
@ -347,15 +355,15 @@ fn convert_abi(a: RustcAbi) -> Abi {
}
}
fn convert_lifetime(l: clean::Lifetime) -> String {
l.0.to_string()
}
impl FromWithTcx<clean::Generics> for Generics {
fn from_tcx(generics: clean::Generics, tcx: TyCtxt<'_>) -> Self {
Generics {
params: generics.params.into_iter().map(|x| x.into_tcx(tcx)).collect(),
where_predicates: generics
.where_predicates
.into_iter()
.map(|x| x.into_tcx(tcx))
.collect(),
params: generics.params.into_tcx(tcx),
where_predicates: generics.where_predicates.into_tcx(tcx),
}
}
}
@ -374,10 +382,10 @@ impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind {
use clean::GenericParamDefKind::*;
match kind {
Lifetime { outlives } => GenericParamDefKind::Lifetime {
outlives: outlives.into_iter().map(|lt| lt.0.to_string()).collect(),
outlives: outlives.into_iter().map(convert_lifetime).collect(),
},
Type { did: _, bounds, default, synthetic } => GenericParamDefKind::Type {
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
bounds: bounds.into_tcx(tcx),
default: default.map(|x| (*x).into_tcx(tcx)),
synthetic,
},
@ -395,7 +403,7 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate {
match predicate {
BoundPredicate { ty, bounds, bound_params } => WherePredicate::BoundPredicate {
type_: ty.into_tcx(tcx),
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
bounds: bounds.into_tcx(tcx),
generic_params: bound_params
.into_iter()
.map(|x| GenericParamDef {
@ -405,8 +413,8 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate {
.collect(),
},
RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate {
lifetime: lifetime.0.to_string(),
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
lifetime: convert_lifetime(lifetime),
bounds: bounds.into_tcx(tcx),
},
EqPredicate { lhs, rhs } => {
WherePredicate::EqPredicate { lhs: lhs.into_tcx(tcx), rhs: rhs.into_tcx(tcx) }
@ -424,11 +432,11 @@ impl FromWithTcx<clean::GenericBound> for GenericBound {
let trait_ = clean::Type::Path { path: trait_ }.into_tcx(tcx);
GenericBound::TraitBound {
trait_,
generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(),
generic_params: generic_params.into_tcx(tcx),
modifier: from_trait_bound_modifier(modifier),
}
}
Outlives(lifetime) => GenericBound::Outlives(lifetime.0.to_string()),
Outlives(lifetime) => GenericBound::Outlives(convert_lifetime(lifetime)),
}
}
}
@ -447,8 +455,8 @@ pub(crate) fn from_trait_bound_modifier(
impl FromWithTcx<clean::Type> for Type {
fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
use clean::Type::{
Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive,
QPath, RawPointer, Slice, Tuple,
Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath,
RawPointer, Slice, Tuple,
};
match ty {
@ -458,40 +466,24 @@ impl FromWithTcx<clean::Type> for Type {
args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))),
param_names: Vec::new(),
},
DynTrait(mut bounds, lt) => {
let first_trait = bounds.remove(0).trait_;
Type::ResolvedPath {
name: first_trait.whole_name(),
id: from_item_id(first_trait.def_id().into(), tcx),
args: first_trait
.segments
.last()
.map(|args| Box::new(args.clone().args.into_tcx(tcx))),
param_names: bounds
.into_iter()
.map(|t| {
clean::GenericBound::TraitBound(t, rustc_hir::TraitBoundModifier::None)
})
.chain(lt.map(clean::GenericBound::Outlives))
.map(|bound| bound.into_tcx(tcx))
.collect(),
}
}
clean::Type::DynTrait(bounds, lt) => Type::DynTrait(DynTrait {
lifetime: lt.map(convert_lifetime),
traits: bounds.into_tcx(tcx),
}),
Generic(s) => Type::Generic(s.to_string()),
Primitive(p) => Type::Primitive(p.as_sym().to_string()),
BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))),
Tuple(t) => Type::Tuple(t.into_iter().map(|x| x.into_tcx(tcx)).collect()),
Tuple(t) => Type::Tuple(t.into_tcx(tcx)),
Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))),
Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s },
ImplTrait(g) => Type::ImplTrait(g.into_iter().map(|x| x.into_tcx(tcx)).collect()),
ImplTrait(g) => Type::ImplTrait(g.into_tcx(tcx)),
Infer => Type::Infer,
RawPointer(mutability, type_) => Type::RawPointer {
mutable: mutability == ast::Mutability::Mut,
type_: Box::new((*type_).into_tcx(tcx)),
},
BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef {
lifetime: lifetime.map(|l| l.0.to_string()),
lifetime: lifetime.map(convert_lifetime),
mutable: mutability == ast::Mutability::Mut,
type_: Box::new((*type_).into_tcx(tcx)),
},
@ -528,7 +520,7 @@ impl FromWithTcx<clean::BareFunctionDecl> for FunctionPointer {
async_: false,
abi: convert_abi(abi),
},
generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(),
generic_params: generic_params.into_tcx(tcx),
decl: decl.into_tcx(tcx),
}
}
@ -562,16 +554,28 @@ impl FromWithTcx<clean::Trait> for Trait {
is_unsafe,
items: ids(items, tcx),
generics: generics.into_tcx(tcx),
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
bounds: bounds.into_tcx(tcx),
implementations: Vec::new(), // Added in JsonRenderer::item
}
}
}
impl FromWithTcx<Box<clean::Impl>> for Impl {
fn from_tcx(impl_: Box<clean::Impl>, tcx: TyCtxt<'_>) -> Self {
impl FromWithTcx<clean::PolyTrait> for PolyTrait {
fn from_tcx(
clean::PolyTrait { trait_, generic_params }: clean::PolyTrait,
tcx: TyCtxt<'_>,
) -> Self {
PolyTrait {
trait_: clean::Type::Path { path: trait_ }.into_tcx(tcx),
generic_params: generic_params.into_tcx(tcx),
}
}
}
impl FromWithTcx<clean::Impl> for Impl {
fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self {
let provided_trait_methods = impl_.provided_trait_methods(tcx);
let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = *impl_;
let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = impl_;
// FIXME: should `trait_` be a clean::Path equivalent in JSON?
let trait_ = trait_.map(|path| clean::Type::Path { path }.into_tcx(tcx));
// FIXME: use something like ImplKind in JSON?
@ -730,10 +734,7 @@ impl FromWithTcx<Box<clean::Typedef>> for Typedef {
impl FromWithTcx<clean::OpaqueTy> for OpaqueTy {
fn from_tcx(opaque: clean::OpaqueTy, tcx: TyCtxt<'_>) -> Self {
OpaqueTy {
bounds: opaque.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
generics: opaque.generics.into_tcx(tcx),
}
OpaqueTy { bounds: opaque.bounds.into_tcx(tcx), generics: opaque.generics.into_tcx(tcx) }
}
}
@ -749,10 +750,7 @@ impl FromWithTcx<clean::Static> for Static {
impl FromWithTcx<clean::TraitAlias> for TraitAlias {
fn from_tcx(alias: clean::TraitAlias, tcx: TyCtxt<'_>) -> Self {
TraitAlias {
generics: alias.generics.into_tcx(tcx),
params: alias.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
}
TraitAlias { generics: alias.generics.into_tcx(tcx), params: alias.bounds.into_tcx(tcx) }
}
}

View File

@ -9,7 +9,7 @@ use std::path::PathBuf;
use serde::{Deserialize, Serialize};
/// rustdoc format-version.
pub const FORMAT_VERSION: u32 = 16;
pub const FORMAT_VERSION: u32 = 17;
/// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
/// about the language items in the local crate, as well as info about external items to allow
@ -115,6 +115,35 @@ pub enum Visibility {
},
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct DynTrait {
/// All the traits implemented. One of them is the vtable, and the rest must be auto traits.
pub traits: Vec<PolyTrait>,
/// The lifetime of the whole dyn object
/// ```text
/// dyn Debug + 'static
/// ^^^^^^^
/// |
/// this part
/// ```
pub lifetime: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
/// A trait and potential HRTBs
pub struct PolyTrait {
#[serde(rename = "trait")]
pub trait_: Type,
/// Used for Higher-Rank Trait Bounds (HRTBs)
/// ```text
/// dyn for<'a> Fn() -> &'a i32"
/// ^^^^^^^
/// |
/// this part
/// ```
pub generic_params: Vec<GenericParamDef>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum GenericArgs {
@ -395,7 +424,7 @@ pub enum WherePredicate {
type_: Type,
bounds: Vec<GenericBound>,
/// Used for Higher-Rank Trait Bounds (HRTBs)
/// ```plain
/// ```text
/// where for<'a> &'a T: Iterator,"
/// ^^^^^^^
/// |
@ -420,7 +449,7 @@ pub enum GenericBound {
#[serde(rename = "trait")]
trait_: Type,
/// Used for Higher-Rank Trait Bounds (HRTBs)
/// ```plain
/// ```text
/// where F: for<'a, 'b> Fn(&'a u8, &'b u8)
/// ^^^^^^^^^^^
/// |
@ -458,6 +487,7 @@ pub enum Type {
args: Option<Box<GenericArgs>>,
param_names: Vec<GenericBound>,
},
DynTrait(DynTrait),
/// Parameterized types
Generic(String),
/// Fixed-size numeric types (plus int/usize/float), char, arrays, slices, and tuples
@ -505,7 +535,7 @@ pub enum Type {
pub struct FunctionPointer {
pub decl: FnDecl,
/// Used for Higher-Rank Trait Bounds (HRTBs)
/// ```plain
/// ```text
/// for<'c> fn(val: &'c i32) -> i32
/// ^^^^^^^
/// |

View File

@ -1,8 +1,13 @@
// ignore-tidy-linelength
use std::fmt::Debug;
// @count dyn.json "$.index[*][?(@.name=='dyn')].inner.items" 1
// @count dyn.json "$.index[*][?(@.name=='dyn')].inner.items[*]" 3
// @set sync_int_gen = - "$.index[*][?(@.name=='SyncIntGen')].id"
// @is - "$.index[*][?(@.name=='dyn')].inner.items[0]" $sync_int_gen
// @set ref_fn = - "$.index[*][?(@.name=='RefFn')].id"
// @set weird_order = - "$.index[*][?(@.name=='WeirdOrder')].id"
// @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $sync_int_gen
// @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $ref_fn
// @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $weird_order
// @is - "$.index[*][?(@.name=='SyncIntGen')].kind" \"typedef\"
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.generics" '{"params": [], "where_predicates": []}'
@ -10,12 +15,35 @@
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.name" \"Box\"
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.bindings" []
// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args" 1
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\"
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\"
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.name" \"Fn\"
// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[*]" 3
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[0].trait_bound.trait.inner.name" \"Send\"
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[1].trait_bound.trait.inner.name" \"Sync\"
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[2]" "{\"outlives\": \"'static\"}"
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.args" '{"parenthesized": {"inputs": [],"output": {"inner": "i32","kind": "primitive"}}}'
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"dyn_trait\"
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.lifetime" \"\'static\"
// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[*]" 3
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].generic_params" []
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[1].generic_params" []
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[2].generic_params" []
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].trait.inner.name" '"Fn"'
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[1].trait.inner.name" '"Send"'
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[2].trait.inner.name" '"Sync"'
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].trait.inner.args" '{"parenthesized": {"inputs": [],"output": {"inner": "i32","kind": "primitive"}}}'
pub type SyncIntGen = Box<dyn Fn() -> i32 + Send + Sync + 'static>;
// @is - "$.index[*][?(@.name=='RefFn')].kind" \"typedef\"
// @is - "$.index[*][?(@.name=='RefFn')].inner.generics" '{"params": [{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"}],"where_predicates": []}'
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.kind" '"borrowed_ref"'
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.mutable" 'false'
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.lifetime" "\"'a\""
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.kind" '"dyn_trait"'
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.lifetime" null
// @count - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[*]" 1
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]'
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.kind" '"resolved_path"'
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.name" '"Fn"'
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.inputs[0].kind" '"borrowed_ref"'
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.inputs[0].inner.lifetime" "\"'b\""
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.output.kind" '"borrowed_ref"'
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.output.inner.lifetime" "\"'b\""
pub type RefFn<'a> = &'a dyn for<'b> Fn(&'b i32) -> &'b i32;
// @is - "$.index[*][?(@.name=='WeirdOrder')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].trait.inner.name" '"Send"'
// @is - "$.index[*][?(@.name=='WeirdOrder')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[1].trait.inner.name" '"Debug"'
pub type WeirdOrder = Box<dyn Send + Debug>;

View File

@ -0,0 +1,26 @@
// ignore-tidy-linelength
// @has hrtb.json
// @is - "$.index[*][?(@.name=='genfn')].inner.generics.where_predicates[0].bound_predicate.type" '{"inner": "F","kind": "generic"}'
// @is - "$.index[*][?(@.name=='genfn')].inner.generics.where_predicates[0].bound_predicate.generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]'
pub fn genfn<F>(f: F)
where
for<'a, 'b> F: Fn(&'a i32, &'b i32),
{
let zero = 0;
f(&zero, &zero);
}
// @is - "$.index[*][?(@.name=='dynfn')].inner.generics" '{"params": [], "where_predicates": []}'
// @is - "$.index[*][?(@.name=='dynfn')].inner.generics" '{"params": [], "where_predicates": []}'
// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].kind" '"borrowed_ref"'
// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.kind" '"dyn_trait"'
// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.lifetime" null
// @count - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.traits[*]" 1
// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]'
// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.traits[0].trait.inner.name" '"Fn"'
pub fn dynfn(f: &dyn for<'a, 'b> Fn(&'a i32, &'b i32)) {
let zero = 0;
f(&zero, &zero);
}

View File

@ -0,0 +1,13 @@
#![crate_name="first"]
pub mod prelude {
pub use crate::Bot;
}
pub struct Bot;
impl Bot {
pub fn new() -> Bot {
Bot
}
}

View File

@ -0,0 +1,21 @@
// Regression test for #100143
use std::iter::Peekable;
pub struct Span<F: Fn(&i32)> {
inner: Peekable<ConditionalIterator<F>>,
}
pub struct ConditionalIterator<F> {
f: F,
}
// @has 'fn_bound/struct.ConditionalIterator.html' '//h3[@class="code-header in-band"]' 'impl<F: Fn(&i32)> Iterator for ConditionalIterator<F>'
impl<F: Fn(&i32)> Iterator for ConditionalIterator<F> {
type Item = ();
fn next(&mut self) -> Option<Self::Item> {
todo!()
}
}

View File

@ -0,0 +1,20 @@
#![crate_name = "foo"]
// Check that default trait items that are impossible to satisfy
pub trait Foo {
fn needs_sized(&self)
where
Self: Sized,
{}
fn no_needs_sized(&self) {}
}
// @!has foo/struct.Bar.html '//*[@id="method.needs_sized"]//h4[@class="code-header"]' \
// "fn needs_sized"
// @has foo/struct.Bar.html '//*[@id="method.no_needs_sized"]//h4[@class="code-header"]' \
// "fn no_needs_sized"
pub struct Bar([u8]);
impl Foo for Bar {}

View File

@ -0,0 +1,14 @@
// aux-build:issue-100204-aux.rs
// build-aux-docs
// ignore-cross-compile
#![crate_name="second"]
extern crate first;
pub mod prelude {}
// @has first/struct.Bot.html '//h4[@class="code-header"]' 'pub fn new() -> Bot'
// @has second/struct.Bot.html '//h4[@class="code-header"]' 'pub fn new() -> Bot'
#[doc(inline)]
pub use first::*;

View File

@ -57,13 +57,11 @@ LL | a + 1
error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:33:1
|
LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 {
LL | |
LL | | a + 1
| | ----- non-asm is unsupported in naked functions
LL | |
LL | | }
| |_^
LL | pub unsafe extern "C" fn inc(a: u32) -> u32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | a + 1
| ----- non-asm is unsupported in naked functions
error: referencing function parameters is not allowed in naked functions
--> $DIR/naked-functions.rs:42:31
@ -82,12 +80,11 @@ LL | asm!("/* {0} */", in(reg) a, options(noreturn));
error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:48:1
|
LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
LL | |
LL | | (|| a + 1)()
| | ------------ non-asm is unsupported in naked functions
LL | | }
| |_^
LL | pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | (|| a + 1)()
| ------------ non-asm is unsupported in naked functions
error[E0787]: only `const` and `sym` operands are supported in naked functions
--> $DIR/naked-functions.rs:65:10
@ -124,30 +121,25 @@ LL | sym G, options(noreturn),
error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:54:1
|
LL | / pub unsafe extern "C" fn unsupported_operands() {
LL | |
LL | | let mut a = 0usize;
| | ------------------- non-asm is unsupported in naked functions
LL | | let mut b = 0usize;
| | ------------------- non-asm is unsupported in naked functions
LL | | let mut c = 0usize;
| | ------------------- non-asm is unsupported in naked functions
LL | | let mut d = 0usize;
| | ------------------- non-asm is unsupported in naked functions
LL | | let mut e = 0usize;
| | ------------------- non-asm is unsupported in naked functions
... |
LL | | );
LL | | }
| |_^
LL | pub unsafe extern "C" fn unsupported_operands() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | let mut a = 0usize;
| ------------------- non-asm is unsupported in naked functions
LL | let mut b = 0usize;
| ------------------- non-asm is unsupported in naked functions
LL | let mut c = 0usize;
| ------------------- non-asm is unsupported in naked functions
LL | let mut d = 0usize;
| ------------------- non-asm is unsupported in naked functions
LL | let mut e = 0usize;
| ------------------- non-asm is unsupported in naked functions
error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:77:1
|
LL | / pub extern "C" fn missing_assembly() {
LL | |
LL | | }
| |_^
LL | pub extern "C" fn missing_assembly() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0787]: asm in naked functions must use `noreturn` option
--> $DIR/naked-functions.rs:84:5
@ -185,20 +177,17 @@ LL | asm!("", options(noreturn));
error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:82:1
|
LL | / pub extern "C" fn too_many_asm_blocks() {
LL | |
LL | | asm!("");
LL | |
LL | | asm!("");
| | -------- multiple asm blocks are unsupported in naked functions
LL | |
LL | | asm!("");
| | -------- multiple asm blocks are unsupported in naked functions
LL | |
LL | | asm!("", options(noreturn));
| | --------------------------- multiple asm blocks are unsupported in naked functions
LL | | }
| |_^
LL | pub extern "C" fn too_many_asm_blocks() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | asm!("");
| -------- multiple asm blocks are unsupported in naked functions
LL |
LL | asm!("");
| -------- multiple asm blocks are unsupported in naked functions
LL |
LL | asm!("", options(noreturn));
| --------------------------- multiple asm blocks are unsupported in naked functions
error: referencing function parameters is not allowed in naked functions
--> $DIR/naked-functions.rs:97:11
@ -211,13 +200,11 @@ LL | *&y
error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:95:5
|
LL | / pub extern "C" fn inner(y: usize) -> usize {
LL | |
LL | | *&y
| | --- non-asm is unsupported in naked functions
LL | |
LL | | }
| |_____^
LL | pub extern "C" fn inner(y: usize) -> usize {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | *&y
| --- non-asm is unsupported in naked functions
error[E0787]: asm options unsupported in naked functions: `nomem`, `preserves_flags`
--> $DIR/naked-functions.rs:105:5
@ -249,18 +236,18 @@ LL | asm!("", options(noreturn, may_unwind));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: Rust ABI is unsupported in naked functions
--> $DIR/naked-functions.rs:124:15
--> $DIR/naked-functions.rs:124:1
|
LL | pub unsafe fn default_abi() {
| ^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(undefined_naked_function_abi)]` on by default
warning: Rust ABI is unsupported in naked functions
--> $DIR/naked-functions.rs:130:15
--> $DIR/naked-functions.rs:130:1
|
LL | pub unsafe fn rust_abi() {
| ^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: naked functions cannot be inlined
--> $DIR/naked-functions.rs:170:1

View File

@ -4,5 +4,5 @@ trait I32Iterator = Iterator<Item = i32>;
fn main() {
let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
//~^ ERROR type mismatch
//~^ ERROR expected `std::vec::IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
}

View File

@ -1,4 +1,4 @@
error[E0271]: type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == i32`
error[E0271]: expected `std::vec::IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
--> $DIR/associated-types-overridden-binding-2.rs:6:43
|
LL | let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();

View File

@ -15,7 +15,7 @@ fn return_targets_async_block_not_fn() -> u8 {
return 0u8;
};
let _: &dyn Future<Output = ()> = &block;
//~^ ERROR type mismatch
//~^ ERROR expected `impl Future<Output = u8>` to be a future that resolves to `()`, but it resolves to `u8`
}
async fn return_targets_async_block_not_async_fn() -> u8 {
@ -24,7 +24,7 @@ async fn return_targets_async_block_not_async_fn() -> u8 {
return 0u8;
};
let _: &dyn Future<Output = ()> = &block;
//~^ ERROR type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
//~^ ERROR expected `impl Future<Output = u8>` to be a future that resolves to `()`, but it resolves to `u8`
}
fn no_break_in_async_block() {
@ -42,7 +42,9 @@ fn no_break_in_async_block_even_with_outer_loop() {
}
struct MyErr;
fn err() -> Result<u8, MyErr> { Err(MyErr) }
fn err() -> Result<u8, MyErr> {
Err(MyErr)
}
fn rethrow_targets_async_block_not_fn() -> Result<u8, MyErr> {
//~^ ERROR mismatched types

View File

@ -31,7 +31,7 @@ LL | |
LL | | }
| |_^ expected `u8`, found `()`
error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
error[E0271]: expected `impl Future<Output = u8>` to be a future that resolves to `()`, but it resolves to `u8`
--> $DIR/async-block-control-flow-static-semantics.rs:26:39
|
LL | let _: &dyn Future<Output = ()> = &block;
@ -47,7 +47,7 @@ LL | fn return_targets_async_block_not_fn() -> u8 {
| |
| implicitly returns `()` as its body has no tail or `return` expression
error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
error[E0271]: expected `impl Future<Output = u8>` to be a future that resolves to `()`, but it resolves to `u8`
--> $DIR/async-block-control-flow-static-semantics.rs:17:39
|
LL | let _: &dyn Future<Output = ()> = &block;
@ -56,7 +56,7 @@ LL | let _: &dyn Future<Output = ()> = &block;
= note: required for the cast from `impl Future<Output = u8>` to the object type `dyn Future<Output = ()>`
error[E0308]: mismatched types
--> $DIR/async-block-control-flow-static-semantics.rs:47:44
--> $DIR/async-block-control-flow-static-semantics.rs:49:44
|
LL | fn rethrow_targets_async_block_not_fn() -> Result<u8, MyErr> {
| ---------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `Result`, found `()`
@ -67,7 +67,7 @@ LL | fn rethrow_targets_async_block_not_fn() -> Result<u8, MyErr> {
found unit type `()`
error[E0308]: mismatched types
--> $DIR/async-block-control-flow-static-semantics.rs:56:50
--> $DIR/async-block-control-flow-static-semantics.rs:58:50
|
LL | fn rethrow_targets_async_block_not_async_fn() -> Result<u8, MyErr> {
| ---------------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `Result`, found `()`

View File

@ -6,9 +6,9 @@
enum Eu64 {
//~^ ERROR discriminant value `0` assigned more than once
Au64 = 0,
//~^NOTE first assignment of `0`
//~^NOTE `0` assigned here
Bu64 = 0x8000_0000_0000_0000
//~^NOTE second assignment of `0` (overflowed from `9223372036854775808`)
//~^NOTE `0` (overflowed from `9223372036854775808`) assigned here
}
fn main() {}

View File

@ -5,10 +5,10 @@ LL | enum Eu64 {
| ^^^^^^^^^
LL |
LL | Au64 = 0,
| - first assignment of `0`
| - `0` assigned here
LL |
LL | Bu64 = 0x8000_0000_0000_0000
| --------------------- second assignment of `0` (overflowed from `9223372036854775808`)
| --------------------- `0` (overflowed from `9223372036854775808`) assigned here
error: aborting due to previous error

View File

@ -1,9 +1,9 @@
enum Enum {
//~^ ERROR discriminant value `3` assigned more than once
P = 3,
//~^ NOTE first assignment of `3`
//~^ NOTE `3` assigned here
X = 3,
//~^ NOTE second assignment of `3`
//~^ NOTE `3` assigned here
Y = 5
}
@ -11,20 +11,43 @@ enum Enum {
enum EnumOverflowRepr {
//~^ ERROR discriminant value `1` assigned more than once
P = 257,
//~^ NOTE first assignment of `1` (overflowed from `257`)
//~^ NOTE `1` (overflowed from `257`) assigned here
X = 513,
//~^ NOTE second assignment of `1` (overflowed from `513`)
//~^ NOTE `1` (overflowed from `513`) assigned here
}
#[repr(i8)]
enum NegDisEnum {
//~^ ERROR discriminant value `-1` assigned more than once
First = -1,
//~^ NOTE first assignment of `-1`
//~^ NOTE `-1` assigned here
Second = -2,
//~^ NOTE assigned discriminant for `Last` was incremented from this discriminant
//~^ NOTE discriminant for `Last` incremented from this startpoint (`Second` + 1 variant later => `Last` = -1)
Last,
//~^ NOTE second assignment of `-1`
//~^ NOTE `-1` assigned here
}
enum MultipleDuplicates {
//~^ ERROR discriminant value `0` assigned more than once
//~^^ ERROR discriminant value `-2` assigned more than once
V0,
//~^ NOTE `0` assigned here
V1 = 0,
//~^ NOTE `0` assigned here
V2,
V3,
V4 = 0,
//~^ NOTE `0` assigned here
V5 = -2,
//~^ NOTE discriminant for `V7` incremented from this startpoint (`V5` + 2 variants later => `V7` = 0)
//~^^ NOTE `-2` assigned here
V6,
V7,
//~^ NOTE `0` assigned here
V8 = -3,
//~^ NOTE discriminant for `V9` incremented from this startpoint (`V8` + 1 variant later => `V9` = -2)
V9,
//~^ NOTE `-2` assigned here
}
fn main() {

View File

@ -5,10 +5,10 @@ LL | enum Enum {
| ^^^^^^^^^
LL |
LL | P = 3,
| - first assignment of `3`
| - `3` assigned here
LL |
LL | X = 3,
| - second assignment of `3`
| - `3` assigned here
error[E0081]: discriminant value `1` assigned more than once
--> $DIR/E0081.rs:11:1
@ -17,10 +17,10 @@ LL | enum EnumOverflowRepr {
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | P = 257,
| --- first assignment of `1` (overflowed from `257`)
| --- `1` (overflowed from `257`) assigned here
LL |
LL | X = 513,
| --- second assignment of `1` (overflowed from `513`)
| --- `1` (overflowed from `513`) assigned here
error[E0081]: discriminant value `-1` assigned more than once
--> $DIR/E0081.rs:20:1
@ -29,14 +29,50 @@ LL | enum NegDisEnum {
| ^^^^^^^^^^^^^^^
LL |
LL | First = -1,
| -- first assignment of `-1`
| -- `-1` assigned here
LL |
LL | Second = -2,
| ----------- assigned discriminant for `Last` was incremented from this discriminant
| ----------- discriminant for `Last` incremented from this startpoint (`Second` + 1 variant later => `Last` = -1)
LL |
LL | Last,
| ---- second assignment of `-1`
| ---- `-1` assigned here
error: aborting due to 3 previous errors
error[E0081]: discriminant value `0` assigned more than once
--> $DIR/E0081.rs:30:1
|
LL | enum MultipleDuplicates {
| ^^^^^^^^^^^^^^^^^^^^^^^
...
LL | V0,
| -- `0` assigned here
LL |
LL | V1 = 0,
| - `0` assigned here
...
LL | V4 = 0,
| - `0` assigned here
LL |
LL | V5 = -2,
| ------- discriminant for `V7` incremented from this startpoint (`V5` + 2 variants later => `V7` = 0)
...
LL | V7,
| -- `0` assigned here
error[E0081]: discriminant value `-2` assigned more than once
--> $DIR/E0081.rs:30:1
|
LL | enum MultipleDuplicates {
| ^^^^^^^^^^^^^^^^^^^^^^^
...
LL | V5 = -2,
| -- `-2` assigned here
...
LL | V8 = -3,
| ------- discriminant for `V9` incremented from this startpoint (`V8` + 1 variant later => `V9` = -2)
LL |
LL | V9,
| -- `-2` assigned here
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0081`.

View File

@ -38,9 +38,13 @@ fn main() {
let v = Unit2.m(
//~^ ERROR type mismatch
L {
//~^ ERROR type mismatch
f : |x| { drop(x); Unit4 }
});
//~^ ERROR to be a closure that returns `Unit3`, but it returns `Unit4`
f: |x| {
drop(x);
Unit4
},
},
);
}
impl<'a> Ty<'a> for Unit2 {

View File

@ -1,8 +1,8 @@
error[E0271]: type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
error[E0271]: type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
--> $DIR/issue-62203-hrtb-ice.rs:38:19
|
LL | let v = Unit2.m(
| ^ type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
| ^ type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
|
note: expected this to be `<_ as Ty<'_>>::V`
--> $DIR/issue-62203-hrtb-ice.rs:21:14
@ -22,7 +22,7 @@ LL | where
LL | F: for<'r> T0<'r, (<Self as Ty<'r>>::V,), O = <B as Ty<'r>>::V>,
| ^^^^^^^^^^^^^^^^^^^^ required by this bound in `T1::m`
error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20] as FnOnce<((&'r u8,),)>>::Output == Unit3`
error[E0271]: expected `[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]` to be a closure that returns `Unit3`, but it returns `Unit4`
--> $DIR/issue-62203-hrtb-ice.rs:40:9
|
LL | let v = Unit2.m(
@ -30,11 +30,14 @@ LL | let v = Unit2.m(
LL |
LL | / L {
LL | |
LL | | f : |x| { drop(x); Unit4 }
LL | | });
LL | | f: |x| {
LL | | drop(x);
LL | | Unit4
LL | | },
LL | | },
| |_________^ expected struct `Unit3`, found struct `Unit4`
|
note: required because of the requirements on the impl of `for<'r> T0<'r, (&'r u8,)>` for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]>`
note: required because of the requirements on the impl of `for<'r> T0<'r, (&'r u8,)>` for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]>`
--> $DIR/issue-62203-hrtb-ice.rs:17:16
|
LL | impl<'a, A, T> T0<'a, A> for L<T>

View File

@ -7,7 +7,7 @@ type F = impl core::future::Future<Output = u8>;
struct Bug {
V1: [(); {
fn concrete_use() -> F {
//~^ ERROR type mismatch
//~^ ERROR expected `impl Future<Output = ()>` to be a future that resolves to `u8`, but it resolves to `()`
async {}
}
let f: F = async { 1 };

View File

@ -16,7 +16,7 @@ LL | let f: F = async { 1 };
LL | }],
| - value is dropped here
error[E0271]: type mismatch resolving `<impl Future<Output = ()> as Future>::Output == u8`
error[E0271]: expected `impl Future<Output = ()>` to be a future that resolves to `u8`, but it resolves to `()`
--> $DIR/issue-78722.rs:9:30
|
LL | fn concrete_use() -> F {

View File

@ -27,7 +27,7 @@ fn baz(n: bool) -> i32 {
const fn return_ty_mismatch() {
const_eval_select((1,), foo, bar);
//~^ ERROR type mismatch
//~^ ERROR expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it returns `bool`
}
const fn args_ty_mismatch() {

View File

@ -51,7 +51,7 @@ note: required by a bound in `const_eval_select`
LL | G: FnOnce<ARG, Output = RET> + ~const Destruct,
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
error[E0271]: type mismatch resolving `<fn(i32) -> bool {bar} as FnOnce<(i32,)>>::Output == i32`
error[E0271]: expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it returns `bool`
--> $DIR/const-eval-select-bad.rs:29:5
|
LL | const_eval_select((1,), foo, bar);

View File

@ -1,16 +0,0 @@
const N: isize = 1;
enum Foo {
//~^ ERROR discriminant value `1` assigned more than once
//~| ERROR discriminant value `1` assigned more than once
//~| ERROR discriminant value `1` assigned more than once
A = 1,
B = 1,
C = 0,
D,
E = N,
}
fn main() {}

View File

@ -1,40 +0,0 @@
error[E0081]: discriminant value `1` assigned more than once
--> $DIR/issue-15524.rs:3:1
|
LL | enum Foo {
| ^^^^^^^^
...
LL | A = 1,
| - first assignment of `1`
LL | B = 1,
| - second assignment of `1`
error[E0081]: discriminant value `1` assigned more than once
--> $DIR/issue-15524.rs:3:1
|
LL | enum Foo {
| ^^^^^^^^
...
LL | A = 1,
| - first assignment of `1`
LL | B = 1,
LL | C = 0,
| ----- assigned discriminant for `D` was incremented from this discriminant
LL | D,
| - second assignment of `1`
error[E0081]: discriminant value `1` assigned more than once
--> $DIR/issue-15524.rs:3:1
|
LL | enum Foo {
| ^^^^^^^^
...
LL | A = 1,
| - first assignment of `1`
...
LL | E = N,
| - second assignment of `1`
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0081`.

View File

@ -3,12 +3,13 @@ use std::vec::IntoIter;
pub fn get_tok(it: &mut IntoIter<u8>) {
let mut found_e = false;
let temp: Vec<u8> = it.take_while(|&x| {
found_e = true;
false
})
let temp: Vec<u8> = it
.take_while(|&x| {
found_e = true;
false
})
.cloned()
//~^ ERROR type mismatch resolving
//~^ ERROR to be an iterator that yields `&_`, but it yields `u8`
.collect(); //~ ERROR the method
}

View File

@ -1,5 +1,5 @@
error[E0271]: type mismatch resolving `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]> as Iterator>::Item == &_`
--> $DIR/issue-31173.rs:10:10
error[E0271]: expected `TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>` to be an iterator that yields `&_`, but it yields `u8`
--> $DIR/issue-31173.rs:11:10
|
LL | .cloned()
| ^^^^^^ expected reference, found `u8`
@ -12,11 +12,11 @@ note: required by a bound in `cloned`
LL | Self: Sized + Iterator<Item = &'a T>,
| ^^^^^^^^^^^^ required by this bound in `cloned`
error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>`, but its trait bounds were not satisfied
--> $DIR/issue-31173.rs:12:10
error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>`, but its trait bounds were not satisfied
--> $DIR/issue-31173.rs:13:10
|
LL | .collect();
| ^^^^^^^ method cannot be called on `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>` due to unsatisfied trait bounds
| ^^^^^^^ method cannot be called on `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>` due to unsatisfied trait bounds
|
::: $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL
|
@ -29,10 +29,10 @@ LL | pub struct TakeWhile<I, P> {
| -------------------------- doesn't satisfy `<_ as Iterator>::Item = &_`
|
= note: the following trait bounds were not satisfied:
`<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]> as Iterator>::Item = &_`
which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator`
`Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator`
which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator`
`<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]> as Iterator>::Item = &_`
which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
`Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
error: aborting due to 2 previous errors

View File

@ -3,7 +3,7 @@
use std::collections::HashMap;
fn main() {
for _ in HashMap::new().iter().cloned() {} //~ ERROR type mismatch
//~^ ERROR type mismatch
//~| ERROR type mismatch
for _ in HashMap::new().iter().cloned() {} //~ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
//~^ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
//~| ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
}

View File

@ -1,4 +1,4 @@
error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as Iterator>::Item == &_`
error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
--> $DIR/issue-33941.rs:6:36
|
LL | for _ in HashMap::new().iter().cloned() {}
@ -12,7 +12,7 @@ note: required by a bound in `cloned`
LL | Self: Sized + Iterator<Item = &'a T>,
| ^^^^^^^^^^^^ required by this bound in `cloned`
error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as Iterator>::Item == &_`
error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
--> $DIR/issue-33941.rs:6:14
|
LL | for _ in HashMap::new().iter().cloned() {}
@ -23,7 +23,7 @@ LL | for _ in HashMap::new().iter().cloned() {}
= note: required because of the requirements on the impl of `Iterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
= note: required because of the requirements on the impl of `IntoIterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as Iterator>::Item == &_`
error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
--> $DIR/issue-33941.rs:6:14
|
LL | for _ in HashMap::new().iter().cloned() {}

View File

@ -0,0 +1,18 @@
// force-host
// no-prefer-dynamic
#![crate_type = "proc-macro"]
#![feature(proc_macro_quote)]
extern crate proc_macro;
use proc_macro::{quote, Ident, Span, TokenStream, TokenTree};
#[proc_macro_attribute]
pub fn struct_with_bound(_: TokenStream, _: TokenStream) -> TokenStream {
let crate_ident = TokenTree::Ident(Ident::new("crate", Span::call_site()));
let trait_ident = TokenTree::Ident(Ident::new("MyTrait", Span::call_site()));
quote!(
struct Foo<T: $crate_ident::$trait_ident> {}
)
}

View File

@ -0,0 +1,16 @@
#[issue_100199::struct_with_bound] //~ ERROR cannot find trait `MyTrait` in the crate root
struct Foo {}
// The above must be on the first line so that it's span points to pos 0.
// This used to trigger an ICE because the diagnostic emitter would get
// an unexpected dummy span (lo == 0 == hi) while attempting to print a
// suggestion.
// aux-build: issue-100199.rs
extern crate issue_100199;
mod traits {
pub trait MyTrait {}
}
fn main() {}

View File

@ -0,0 +1,15 @@
error[E0405]: cannot find trait `MyTrait` in the crate root
--> $DIR/issue-100199.rs:1:1
|
LL | #[issue_100199::struct_with_bound]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in the crate root
|
= note: this error originates in the attribute macro `issue_100199::struct_with_bound` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing this trait
|
LL | use traits::MyTrait;
|
error: aborting due to previous error
For more information about this error, try `rustc --explain E0405`.

View File

@ -1,4 +1,4 @@
error[E0271]: type mismatch resolving `<[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47] as FnOnce<()>>::Output == ()`
error[E0271]: expected `[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47]` to be a closure that returns `()`, but it returns `!`
--> $DIR/fallback-closure-wrap.rs:18:31
|
LL | let error = Closure::wrap(Box::new(move || {

View File

@ -16,7 +16,7 @@ use std::marker::PhantomData;
fn main() {
let error = Closure::wrap(Box::new(move || {
//[fallback]~^ ERROR type mismatch resolving
//[fallback]~^ to be a closure that returns `()`, but it returns `!`
panic!("Can't connect to server.");
}) as Box<dyn FnMut()>);
}

View File

@ -0,0 +1,10 @@
// run-rustfix
fn main() {
match Some(1) { //~ ERROR non-exhaustive patterns: `None` not covered
Some(1) => {}
// hello
Some(_) => {}
None => todo!()
}
}

View File

@ -0,0 +1,9 @@
// run-rustfix
fn main() {
match Some(1) { //~ ERROR non-exhaustive patterns: `None` not covered
Some(1) => {}
// hello
Some(_) => {}
}
}

View File

@ -0,0 +1,24 @@
error[E0004]: non-exhaustive patterns: `None` not covered
--> $DIR/suggest-adding-appropriate-missing-pattern-excluding-comments.rs:4:11
|
LL | match Some(1) {
| ^^^^^^^ pattern `None` not covered
|
note: `Option<i32>` defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
|
LL | pub enum Option<T> {
| ------------------
...
LL | None,
| ^^^^ not covered
= note: the matched value is of type `Option<i32>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
LL ~ Some(_) => {}
LL + None => todo!()
|
error: aborting due to previous error
For more information about this error, try `rustc --explain E0004`.

View File

@ -0,0 +1,19 @@
// force-host
// no-prefer-dynamic
#![crate_type = "proc-macro"]
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro]
pub fn cause_ice(_: TokenStream) -> TokenStream {
"
enum IceCause {
Variant,
}
pub use IceCause::Variant;
".parse().unwrap()
}

View File

@ -0,0 +1,10 @@
// aux-build:re-export.rs
// edition:2018
extern crate re_export;
use re_export::cause_ice;
cause_ice!(); //~ ERROR `Variant` is only public within the crate, and cannot be re-exported outside
fn main() {}

View File

@ -0,0 +1,16 @@
error[E0364]: `Variant` is only public within the crate, and cannot be re-exported outside
--> $DIR/issue-79148.rs:8:1
|
LL | cause_ice!();
| ^^^^^^^^^^^^
|
note: consider marking `Variant` as `pub` in the imported module
--> $DIR/issue-79148.rs:8:1
|
LL | cause_ice!();
| ^^^^^^^^^^^^
= note: this error originates in the macro `cause_ice` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
For more information about this error, try `rustc --explain E0364`.

View File

@ -0,0 +1,29 @@
#![crate_type = "lib"]
#![feature(staged_api, rustc_attrs)]
#![stable(feature = "stable_feature", since = "1.0.0")]
#[stable(feature = "stable_feature", since = "1.0.0")]
pub trait JustTrait {
#[stable(feature = "stable_feature", since = "1.0.0")]
#[rustc_default_body_unstable(feature = "constant_default_body", issue = "none")]
const CONSTANT: usize = 0;
#[rustc_default_body_unstable(feature = "fun_default_body", issue = "none")]
#[stable(feature = "stable_feature", since = "1.0.0")]
fn fun() {}
}
#[rustc_must_implement_one_of(eq, neq)]
#[stable(feature = "stable_feature", since = "1.0.0")]
pub trait Equal {
#[rustc_default_body_unstable(feature = "eq_default_body", issue = "none")]
#[stable(feature = "stable_feature", since = "1.0.0")]
fn eq(&self, other: &Self) -> bool {
!self.neq(other)
}
#[stable(feature = "stable_feature", since = "1.0.0")]
fn neq(&self, other: &Self) -> bool {
!self.eq(other)
}
}

View File

@ -0,0 +1,19 @@
// aux-build:default_body.rs
#![crate_type = "lib"]
extern crate default_body;
use default_body::{Equal, JustTrait};
struct Type;
impl JustTrait for Type {}
//~^ ERROR not all trait items implemented, missing: `CONSTANT` [E0046]
//~| ERROR not all trait items implemented, missing: `fun` [E0046]
impl Equal for Type {
//~^ ERROR not all trait items implemented, missing: `eq` [E0046]
fn neq(&self, other: &Self) -> bool {
false
}
}

View File

@ -0,0 +1,38 @@
error[E0046]: not all trait items implemented, missing: `CONSTANT`
--> $DIR/default-body-stability-err.rs:10:1
|
LL | impl JustTrait for Type {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: default implementation of `CONSTANT` is unstable
= note: use of unstable library feature 'constant_default_body'
= help: add `#![feature(constant_default_body)]` to the crate attributes to enable
error[E0046]: not all trait items implemented, missing: `fun`
--> $DIR/default-body-stability-err.rs:10:1
|
LL | impl JustTrait for Type {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: default implementation of `fun` is unstable
= note: use of unstable library feature 'fun_default_body'
= help: add `#![feature(fun_default_body)]` to the crate attributes to enable
error[E0046]: not all trait items implemented, missing: `eq`
--> $DIR/default-body-stability-err.rs:14:1
|
LL | / impl Equal for Type {
LL | |
LL | | fn neq(&self, other: &Self) -> bool {
LL | | false
LL | | }
LL | | }
| |_^
|
= note: default implementation of `eq` is unstable
= note: use of unstable library feature 'eq_default_body'
= help: add `#![feature(eq_default_body)]` to the crate attributes to enable
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0046`.

View File

@ -0,0 +1,18 @@
// check-pass
// aux-build:default_body.rs
#![crate_type = "lib"]
#![feature(fun_default_body, eq_default_body, constant_default_body)]
extern crate default_body;
use default_body::{Equal, JustTrait};
struct Type;
impl JustTrait for Type {}
impl Equal for Type {
fn neq(&self, other: &Self) -> bool {
false
}
}

View File

@ -0,0 +1,21 @@
// check-pass
// aux-build:default_body.rs
#![crate_type = "lib"]
extern crate default_body;
use default_body::{Equal, JustTrait};
struct Type;
impl JustTrait for Type {
const CONSTANT: usize = 1;
fn fun() {}
}
impl Equal for Type {
fn eq(&self, other: &Self) -> bool {
false
}
}

View File

@ -1,12 +0,0 @@
// Black and White have the same discriminator value ...
enum Color {
//~^ ERROR discriminant value `0` assigned more than once
Red = 0xff0000,
Green = 0x00ff00,
Blue = 0x0000ff,
Black = 0x000000,
White = 0x000000,
}
fn main() { }

View File

@ -1,14 +0,0 @@
error[E0081]: discriminant value `0` assigned more than once
--> $DIR/tag-variant-disr-dup.rs:3:1
|
LL | enum Color {
| ^^^^^^^^^^
...
LL | Black = 0x000000,
| -------- first assignment of `0`
LL | White = 0x000000,
| -------- second assignment of `0`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0081`.

View File

@ -4,13 +4,13 @@
use std::vec::IntoIter;
pub trait Foo: Iterator<Item=<Self as Foo>::Key> {
pub trait Foo: Iterator<Item = <Self as Foo>::Key> {
type Key;
}
impl Foo for IntoIter<i32> {
type Key = u32; //~ ERROR type mismatch
type Key = u32;
//~^ ERROR expected `std::vec::IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
}
fn main() {
}
fn main() {}

View File

@ -1,4 +1,4 @@
error[E0271]: type mismatch resolving `<std::vec::IntoIter<i32> as Iterator>::Item == u32`
error[E0271]: expected `std::vec::IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
--> $DIR/assoc-type-in-superbad.rs:12:16
|
LL | type Key = u32;
@ -7,8 +7,8 @@ LL | type Key = u32;
note: required by a bound in `Foo`
--> $DIR/assoc-type-in-superbad.rs:7:25
|
LL | pub trait Foo: Iterator<Item=<Self as Foo>::Key> {
| ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo`
LL | pub trait Foo: Iterator<Item = <Self as Foo>::Key> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo`
error: aborting due to previous error

View File

@ -8,7 +8,7 @@ trait Foo {
impl Foo for () {
type Bar = std::vec::IntoIter<u32>;
//~^ ERROR type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == X
//~^ ERROR expected `std::vec::IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
}
fn incoherent() {

View File

@ -1,4 +1,4 @@
error[E0271]: type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == X`
error[E0271]: expected `std::vec::IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
--> $DIR/issue-57961.rs:10:16
|
LL | type X = impl Sized;

View File

@ -1,13 +1,11 @@
// edition:2018
type AsyncFnPtr = Box<
dyn Fn() -> std::pin::Pin<Box<dyn std::future::Future<Output = ()>>>,
>;
type AsyncFnPtr = Box<dyn Fn() -> std::pin::Pin<Box<dyn std::future::Future<Output = ()>>>>;
async fn test() {}
#[allow(unused_must_use)]
fn main() {
Box::new(test) as AsyncFnPtr;
//~^ ERROR type mismatch
//~^ ERROR expected `fn() -> impl Future<Output = ()> {test}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it returns `impl Future<Output = ()>`
}

View File

@ -1,11 +1,11 @@
error[E0271]: type mismatch resolving `<fn() -> impl Future<Output = ()> {test} as FnOnce<()>>::Output == Pin<Box<(dyn Future<Output = ()> + 'static)>>`
--> $DIR/issue-98604.rs:11:5
error[E0271]: expected `fn() -> impl Future<Output = ()> {test}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it returns `impl Future<Output = ()>`
--> $DIR/issue-98604.rs:9:5
|
LL | Box::new(test) as AsyncFnPtr;
| ^^^^^^^^^^^^^^ expected struct `Pin`, found opaque type
|
note: while checking the return type of the `async fn`
--> $DIR/issue-98604.rs:7:17
--> $DIR/issue-98604.rs:5:17
|
LL | async fn test() {}
| ^ checked the `Output` of this `async fn`, found opaque type

View File

@ -1,8 +1,10 @@
fn hi() -> impl Sized { std::ptr::null::<u8>() }
fn hi() -> impl Sized {
std::ptr::null::<u8>()
}
fn main() {
let b: Box<dyn Fn() -> Box<u8>> = Box::new(hi);
//~^ ERROR type mismatch resolving `<fn() -> impl Sized {hi} as FnOnce<()>>::Output == Box<u8>`
//~^ ERROR expected `fn() -> impl Sized {hi}` to be a fn item that returns `Box<u8>`, but it returns `impl Sized`
let boxed = b();
let null = *boxed;
println!("{null:?}");

View File

@ -1,7 +1,7 @@
error[E0271]: type mismatch resolving `<fn() -> impl Sized {hi} as FnOnce<()>>::Output == Box<u8>`
--> $DIR/issue-98608.rs:4:39
error[E0271]: expected `fn() -> impl Sized {hi}` to be a fn item that returns `Box<u8>`, but it returns `impl Sized`
--> $DIR/issue-98608.rs:6:39
|
LL | fn hi() -> impl Sized { std::ptr::null::<u8>() }
LL | fn hi() -> impl Sized {
| ---------- the found opaque type
...
LL | let b: Box<dyn Fn() -> Box<u8>> = Box::new(hi);

View File

@ -2,9 +2,12 @@ error[E0615]: attempted to take value of method `read` on type `*mut Foo`
--> $DIR/issue-91210-ptr-method.rs:10:7
|
LL | x.read = 4;
| - ^^^^ method, not a field
| |
| help: to access the field, dereference first: `(*x)`
| ^^^^ method, not a field
|
help: to access the field, dereference first
|
LL | (*x).read = 4;
| ++ +
error: aborting due to previous error

View File

@ -19,7 +19,7 @@ Before submitting, please make sure that you're not running into one of these kn
Otherwise please try to provide information which will help us to fix the issue faster. Minimal reproducible examples with few dependencies are especially lovely <3.
-->
**rust-analyzer version**: (eg. output of "Rust Analyzer: Show RA Version" command)
**rust-analyzer version**: (eg. output of "rust-analyzer: Show RA Version" command, accessible in VSCode via <kbd>Ctrl/⌘</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>)
**rustc version**: (eg. output of `rustc -V`)

View File

@ -18,6 +18,7 @@ env:
FETCH_DEPTH: 0 # pull in the tags for the version string
MACOSX_DEPLOYMENT_TARGET: 10.15
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc
jobs:
dist:
@ -36,6 +37,9 @@ jobs:
- os: ubuntu-18.04
target: aarch64-unknown-linux-gnu
code-target: linux-arm64
- os: ubuntu-18.04
target: arm-unknown-linux-gnueabihf
code-target: linux-armhf
- os: macos-11
target: x86_64-apple-darwin
code-target: darwin-x64
@ -67,13 +71,17 @@ jobs:
node-version: 14.x
- name: Update apt repositories
if: matrix.target == 'aarch64-unknown-linux-gnu'
if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf'
run: sudo apt-get update
- name: Install target toolchain
- name: Install AArch64 target toolchain
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: sudo apt-get install gcc-aarch64-linux-gnu
- name: Install ARM target toolchain
if: matrix.target == 'arm-unknown-linux-gnueabihf'
run: sudo apt-get install gcc-arm-linux-gnueabihf
- name: Dist
run: cargo xtask dist --client-patch-version ${{ github.run_number }}
@ -204,6 +212,10 @@ jobs:
with:
name: dist-aarch64-unknown-linux-gnu
path: dist
- uses: actions/download-artifact@v1
with:
name: dist-arm-unknown-linux-gnueabihf
path: dist
- uses: actions/download-artifact@v1
with:
name: dist-x86_64-pc-windows-msvc

View File

@ -43,7 +43,7 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer
## License
Rust analyzer is primarily distributed under the terms of both the MIT
rust-analyzer is primarily distributed under the terms of both the MIT
license and the Apache License (Version 2.0).
See LICENSE-APACHE and LICENSE-MIT for details.

View File

@ -57,6 +57,7 @@ pub struct FlycheckHandle {
// XXX: drop order is significant
sender: Sender<Restart>,
_thread: jod_thread::JoinHandle,
id: usize,
}
impl FlycheckHandle {
@ -72,18 +73,22 @@ impl FlycheckHandle {
.name("Flycheck".to_owned())
.spawn(move || actor.run(receiver))
.expect("failed to spawn thread");
FlycheckHandle { sender, _thread: thread }
FlycheckHandle { id, sender, _thread: thread }
}
/// Schedule a re-start of the cargo check worker.
pub fn update(&self) {
self.sender.send(Restart).unwrap();
}
pub fn id(&self) -> usize {
self.id
}
}
pub enum Message {
/// Request adding a diagnostic with fixes included to a file
AddDiagnostic { workspace_root: AbsPathBuf, diagnostic: Diagnostic },
AddDiagnostic { id: usize, workspace_root: AbsPathBuf, diagnostic: Diagnostic },
/// Request check progress notification to client
Progress {
@ -96,8 +101,9 @@ pub enum Message {
impl fmt::Debug for Message {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Message::AddDiagnostic { workspace_root, diagnostic } => f
Message::AddDiagnostic { id, workspace_root, diagnostic } => f
.debug_struct("AddDiagnostic")
.field("id", id)
.field("workspace_root", workspace_root)
.field("diagnostic_code", &diagnostic.code.as_ref().map(|it| &it.code))
.finish(),
@ -183,7 +189,7 @@ impl FlycheckActor {
}
}
Event::CheckEvent(None) => {
tracing::debug!("flycheck finished");
tracing::debug!(flycheck_id = self.id, "flycheck finished");
// Watcher finished
let cargo_handle = self.cargo_handle.take().unwrap();
@ -203,6 +209,7 @@ impl FlycheckActor {
CargoMessage::Diagnostic(msg) => {
self.send(Message::AddDiagnostic {
id: self.id,
workspace_root: self.workspace_root.clone(),
diagnostic: msg,
});

Some files were not shown because too many files have changed in this diff Show More