[[package]]
name = "libc"
-version = "0.2.88"
+version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a"
+checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41"
dependencies = [
"rustc-std-workspace-core",
]
UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
AbiMismatch(ExpectedFound<abi::Abi>),
Mutability,
+ ArgumentMutability(usize),
TupleSize(ExpectedFound<usize>),
FixedArraySize(ExpectedFound<u64>),
ArgCount,
RegionsPlaceholderMismatch,
Sorts(ExpectedFound<Ty<'tcx>>),
+ ArgumentSorts(ExpectedFound<Ty<'tcx>>, usize),
IntMismatch(ExpectedFound<ty::IntVarValue>),
FloatMismatch(ExpectedFound<ty::FloatTy>),
Traits(ExpectedFound<DefId>),
AbiMismatch(values) => {
write!(f, "expected {} fn, found {} fn", values.expected, values.found)
}
- Mutability => write!(f, "types differ in mutability"),
+ ArgumentMutability(_) | Mutability => write!(f, "types differ in mutability"),
TupleSize(values) => write!(
f,
"expected a tuple with {} element{}, \
br_string(br)
),
RegionsPlaceholderMismatch => write!(f, "one type is more general than the other"),
- Sorts(values) => ty::tls::with(|tcx| {
+ ArgumentSorts(values, _) | Sorts(values) => ty::tls::with(|tcx| {
report_maybe_different(
f,
&values.expected.sort_string(tcx),
use self::TypeError::*;
match self {
CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | Mismatch | AbiMismatch(_)
- | FixedArraySize(_) | Sorts(_) | IntMismatch(_) | FloatMismatch(_)
- | VariadicMismatch(_) | TargetFeatureCast(_) => false,
+ | FixedArraySize(_) | ArgumentSorts(..) | Sorts(_) | IntMismatch(_)
+ | FloatMismatch(_) | VariadicMismatch(_) | TargetFeatureCast(_) => false,
Mutability
+ | ArgumentMutability(_)
| TupleSize(_)
| ArgCount
| RegionsDoesNotOutlive(..)
use self::TypeError::*;
debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause);
match err {
- Sorts(values) => {
+ ArgumentSorts(values, _) | Sorts(values) => {
match (values.expected.kind(), values.found.kind()) {
(ty::Closure(..), ty::Closure(..)) => {
db.note("no two closures, even if identical, have the same type");
} else {
relation.relate_with_variance(ty::Contravariant, a, b)
}
+ })
+ .enumerate()
+ .map(|(i, r)| match r {
+ Err(TypeError::Sorts(exp_found)) => Err(TypeError::ArgumentSorts(exp_found, i)),
+ Err(TypeError::Mutability) => Err(TypeError::ArgumentMutability(i)),
+ r => r,
});
Ok(ty::FnSig {
inputs_and_output: tcx.mk_type_list(inputs_and_output)?,
UnsafetyMismatch(x) => UnsafetyMismatch(x),
AbiMismatch(x) => AbiMismatch(x),
Mutability => Mutability,
+ ArgumentMutability(i) => ArgumentMutability(i),
TupleSize(x) => TupleSize(x),
FixedArraySize(x) => FixedArraySize(x),
ArgCount => ArgCount,
CyclicTy(t) => return tcx.lift(t).map(|t| CyclicTy(t)),
CyclicConst(ct) => return tcx.lift(ct).map(|ct| CyclicConst(ct)),
ProjectionMismatched(x) => ProjectionMismatched(x),
+ ArgumentSorts(x, i) => return tcx.lift(x).map(|x| ArgumentSorts(x, i)),
Sorts(x) => return tcx.lift(x).map(Sorts),
ExistentialMismatch(x) => return tcx.lift(x).map(ExistentialMismatch),
ConstMismatch(x) => return tcx.lift(x).map(ConstMismatch),
}
ItemKind::Static(ref ty, _, ref expr) | ItemKind::Const(_, ref ty, ref expr) => {
- debug!("resolve_item ItemKind::Const");
self.with_item_rib(HasGenericParams::No, |this| {
this.visit_ty(ty);
if let Some(expr) = expr {
.try_resolve_as_non_binding(pat_src, pat, bmode, ident, has_sub)
.unwrap_or_else(|| self.fresh_binding(ident, pat.id, pat_src, bindings));
self.r.record_partial_res(pat.id, PartialRes::new(res));
+ self.r.record_pat_span(pat.id, pat.span);
}
PatKind::TupleStruct(ref path, ref sub_patterns) => {
self.smart_resolve_path(
/// "self-confirming" import resolutions during import validation.
unusable_binding: Option<&'a NameBinding<'a>>,
+ // Spans for local variables found during pattern resolution.
+ // Used for suggestions during error reporting.
+ pat_span_map: NodeMap<Span>,
+
/// Resolutions for nodes that have a single resolution.
partial_res_map: NodeMap<PartialRes>,
/// Resolutions for import nodes, which have multiple resolutions in different namespaces.
last_import_segment: false,
unusable_binding: None,
+ pat_span_map: Default::default(),
partial_res_map: Default::default(),
import_res_map: Default::default(),
label_res_map: Default::default(),
return Some(LexicalScopeBinding::Item(binding));
}
}
-
self.early_resolve_ident_in_lexical_scope(
orig_ident,
ScopeSet::Late(ns, module, record_used_id),
.next()
.map_or(false, |c| c.is_ascii_uppercase())
{
- (format!("use of undeclared type `{}`", ident), None)
+ // Check whether the name refers to an item in the value namespace.
+ let suggestion = if ribs.is_some() {
+ let match_span = match self.resolve_ident_in_lexical_scope(
+ ident,
+ ValueNS,
+ parent_scope,
+ None,
+ path_span,
+ &ribs.unwrap()[ValueNS],
+ ) {
+ // Name matches a local variable. For example:
+ // ```
+ // fn f() {
+ // let Foo: &str = "";
+ // println!("{}", Foo::Bar); // Name refers to local
+ // // variable `Foo`.
+ // }
+ // ```
+ Some(LexicalScopeBinding::Res(Res::Local(id))) => {
+ Some(*self.pat_span_map.get(&id).unwrap())
+ }
+
+ // Name matches item from a local name binding
+ // created by `use` declaration. For example:
+ // ```
+ // pub Foo: &str = "";
+ //
+ // mod submod {
+ // use super::Foo;
+ // println!("{}", Foo::Bar); // Name refers to local
+ // // binding `Foo`.
+ // }
+ // ```
+ Some(LexicalScopeBinding::Item(name_binding)) => {
+ Some(name_binding.span)
+ }
+ _ => None,
+ };
+
+ if let Some(span) = match_span {
+ Some((
+ vec![(span, String::from(""))],
+ format!("`{}` is defined here, but is not a type", ident),
+ Applicability::MaybeIncorrect,
+ ))
+ } else {
+ None
+ }
+ } else {
+ None
+ };
+
+ (format!("use of undeclared type `{}`", ident), suggestion)
} else {
(format!("use of undeclared crate or module `{}`", ident), None)
}
}
}
+ fn record_pat_span(&mut self, node: NodeId, span: Span) {
+ debug!("(recording pat) recording {:?} for {:?}", node, span);
+ self.pat_span_map.insert(node, span);
+ }
+
fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool {
vis.is_accessible_from(module.nearest_parent_mod, self)
}
if let Err(terr) = sub_result {
debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
- let (impl_err_span, trait_err_span) = extract_spans_for_error_reporting(
- &infcx, param_env, &terr, &cause, impl_m, impl_sig, trait_m, trait_sig,
- );
+ let (impl_err_span, trait_err_span) =
+ extract_spans_for_error_reporting(&infcx, &terr, &cause, impl_m, trait_m);
cause.make_mut().span = impl_err_span;
"method `{}` has an incompatible type for trait",
trait_m.ident
);
- if let TypeError::Mutability = terr {
- if let Some(trait_err_span) = trait_err_span {
- if let Ok(trait_err_str) = tcx.sess.source_map().span_to_snippet(trait_err_span)
+ match &terr {
+ TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
+ if trait_m.fn_has_self_parameter =>
+ {
+ let ty = trait_sig.inputs()[0];
+ let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty())
{
+ ExplicitSelf::ByValue => "self".to_owned(),
+ ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
+ ExplicitSelf::ByReference(_, hir::Mutability::Mut) => {
+ "&mut self".to_owned()
+ }
+ _ => format!("self: {}", ty),
+ };
+
+ // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
+ // span points only at the type `Box<Self`>, but we want to cover the whole
+ // argument pattern and type.
+ let impl_m_hir_id =
+ tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
+ let span = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
+ ImplItemKind::Fn(ref sig, body) => tcx
+ .hir()
+ .body_param_names(body)
+ .zip(sig.decl.inputs.iter())
+ .map(|(param, ty)| param.span.to(ty.span))
+ .next()
+ .unwrap_or(impl_err_span),
+ _ => bug!("{:?} is not a method", impl_m),
+ };
+
+ diag.span_suggestion(
+ span,
+ "change the self-receiver type to match the trait",
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ }
+ TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
+ if trait_sig.inputs().len() == *i {
+ // Suggestion to change output type. We do not suggest in `async` functions
+ // to avoid complex logic or incorrect output.
+ let impl_m_hir_id =
+ tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
+ match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
+ ImplItemKind::Fn(ref sig, _)
+ if sig.header.asyncness == hir::IsAsync::NotAsync =>
+ {
+ let msg = "change the output type to match the trait";
+ let ap = Applicability::MachineApplicable;
+ match sig.decl.output {
+ hir::FnRetTy::DefaultReturn(sp) => {
+ let sugg = format!("-> {} ", trait_sig.output());
+ diag.span_suggestion_verbose(sp, msg, sugg, ap);
+ }
+ hir::FnRetTy::Return(hir_ty) => {
+ let sugg = trait_sig.output().to_string();
+ diag.span_suggestion(hir_ty.span, msg, sugg, ap);
+ }
+ };
+ }
+ _ => {}
+ };
+ } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
diag.span_suggestion(
impl_err_span,
- "consider changing the mutability to match the trait",
- trait_err_str,
+ "change the parameter type to match the trait",
+ trait_ty.to_string(),
Applicability::MachineApplicable,
);
}
}
+ _ => {}
}
infcx.note_type_err(
fn extract_spans_for_error_reporting<'a, 'tcx>(
infcx: &infer::InferCtxt<'a, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
terr: &TypeError<'_>,
cause: &ObligationCause<'tcx>,
impl_m: &ty::AssocItem,
- impl_sig: ty::FnSig<'tcx>,
trait_m: &ty::AssocItem,
- trait_sig: ty::FnSig<'tcx>,
) -> (Span, Option<Span>) {
let tcx = infcx.tcx;
let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
- let (impl_m_output, impl_m_iter) = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
- ImplItemKind::Fn(ref impl_m_sig, _) => {
- (&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter())
+ let mut impl_args = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
+ ImplItemKind::Fn(ref sig, _) => {
+ sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
}
_ => bug!("{:?} is not a method", impl_m),
};
-
- match *terr {
- TypeError::Mutability => {
- if let Some(def_id) = trait_m.def_id.as_local() {
- let trait_m_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let trait_m_iter = match tcx.hir().expect_trait_item(trait_m_hir_id).kind {
- TraitItemKind::Fn(ref trait_m_sig, _) => trait_m_sig.decl.inputs.iter(),
- _ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
- };
-
- iter::zip(impl_m_iter, trait_m_iter)
- .find(|&(ref impl_arg, ref trait_arg)| {
- match (&impl_arg.kind, &trait_arg.kind) {
- (
- &hir::TyKind::Rptr(_, ref impl_mt),
- &hir::TyKind::Rptr(_, ref trait_mt),
- )
- | (&hir::TyKind::Ptr(ref impl_mt), &hir::TyKind::Ptr(ref trait_mt)) => {
- impl_mt.mutbl != trait_mt.mutbl
- }
- _ => false,
- }
- })
- .map(|(ref impl_arg, ref trait_arg)| (impl_arg.span, Some(trait_arg.span)))
- .unwrap_or_else(|| (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id)))
- } else {
- (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id))
+ let trait_args = trait_m.def_id.as_local().map(|def_id| {
+ let trait_m_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ match tcx.hir().expect_trait_item(trait_m_hir_id).kind {
+ TraitItemKind::Fn(ref sig, _) => {
+ sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
}
+ _ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
}
- TypeError::Sorts(ExpectedFound { .. }) => {
- if let Some(def_id) = trait_m.def_id.as_local() {
- let trait_m_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let (trait_m_output, trait_m_iter) =
- match tcx.hir().expect_trait_item(trait_m_hir_id).kind {
- TraitItemKind::Fn(ref trait_m_sig, _) => {
- (&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter())
- }
- _ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
- };
+ });
- let impl_iter = impl_sig.inputs().iter();
- let trait_iter = trait_sig.inputs().iter();
- iter::zip(iter::zip(impl_iter, trait_iter), iter::zip(impl_m_iter, trait_m_iter))
- .find_map(|((&impl_arg_ty, &trait_arg_ty), (impl_arg, trait_arg))| match infcx
- .at(&cause, param_env)
- .sub(trait_arg_ty, impl_arg_ty)
- {
- Ok(_) => None,
- Err(_) => Some((impl_arg.span, Some(trait_arg.span))),
- })
- .unwrap_or_else(|| {
- if infcx
- .at(&cause, param_env)
- .sup(trait_sig.output(), impl_sig.output())
- .is_err()
- {
- (impl_m_output.span(), Some(trait_m_output.span()))
- } else {
- (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id))
- }
- })
- } else {
- (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id))
- }
+ match *terr {
+ TypeError::ArgumentMutability(i) => {
+ (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
+ }
+ TypeError::ArgumentSorts(ExpectedFound { .. }, i) => {
+ (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
}
_ => (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id)),
}
tcx.sess,
impl_m_span,
E0185,
- "method `{}` has a `{}` declaration in the impl, but \
- not in the trait",
+ "method `{}` has a `{}` declaration in the impl, but not in the trait",
trait_m.ident,
self_descr
);
tcx.sess,
impl_m_span,
E0186,
- "method `{}` has a `{}` declaration in the trait, but \
- not in the impl",
+ "method `{}` has a `{}` declaration in the trait, but not in the impl",
trait_m.ident,
self_descr
);
tcx.sess,
cause.span,
E0326,
- "implemented const `{}` has an incompatible type for \
- trait",
+ "implemented const `{}` has an incompatible type for trait",
trait_c.ident
);
use crate::fmt;
use crate::hash::{self, Hash};
use crate::iter::TrustedLen;
-use crate::marker::Unsize;
use crate::mem::{self, MaybeUninit};
use crate::ops::{Index, IndexMut};
use crate::slice::{Iter, IterMut};
unsafe { &mut *(s as *mut T).cast::<[T; 1]>() }
}
-/// Utility trait implemented only on arrays of fixed size
-///
-/// This trait can be used to implement other traits on fixed-size arrays
-/// without causing much metadata bloat.
-///
-/// The trait is marked unsafe in order to restrict implementors to fixed-size
-/// arrays. A user of this trait can assume that implementors have the exact
-/// layout in memory of a fixed size array (for example, for unsafe
-/// initialization).
-///
-/// Note that the traits [`AsRef`] and [`AsMut`] provide similar methods for types that
-/// may not be fixed-size arrays. Implementors should prefer those traits
-/// instead.
-#[unstable(feature = "fixed_size_array", issue = "27778")]
-pub unsafe trait FixedSizeArray<T> {
- /// Converts the array to immutable slice
- #[unstable(feature = "fixed_size_array", issue = "27778")]
- fn as_slice(&self) -> &[T];
- /// Converts the array to mutable slice
- #[unstable(feature = "fixed_size_array", issue = "27778")]
- fn as_mut_slice(&mut self) -> &mut [T];
-}
-
-#[unstable(feature = "fixed_size_array", issue = "27778")]
-unsafe impl<T, A: Unsize<[T]>> FixedSizeArray<T> for A {
- #[inline]
- fn as_slice(&self) -> &[T] {
- self
- }
- #[inline]
- fn as_mut_slice(&mut self) -> &mut [T] {
- self
- }
-}
-
/// The error type returned when a conversion from a slice to an array fails.
#[stable(feature = "try_from", since = "1.34.0")]
#[derive(Debug, Copy, Clone)]
-use core::array::{self, FixedSizeArray, IntoIter};
+use core::array::{self, IntoIter};
use core::convert::TryFrom;
-#[test]
-fn fixed_size_array() {
- let mut array = [0; 64];
- let mut zero_sized = [(); 64];
- let mut empty_array = [0; 0];
- let mut empty_zero_sized = [(); 0];
-
- assert_eq!(FixedSizeArray::as_slice(&array).len(), 64);
- assert_eq!(FixedSizeArray::as_slice(&zero_sized).len(), 64);
- assert_eq!(FixedSizeArray::as_slice(&empty_array).len(), 0);
- assert_eq!(FixedSizeArray::as_slice(&empty_zero_sized).len(), 0);
-
- assert_eq!(FixedSizeArray::as_mut_slice(&mut array).len(), 64);
- assert_eq!(FixedSizeArray::as_mut_slice(&mut zero_sized).len(), 64);
- assert_eq!(FixedSizeArray::as_mut_slice(&mut empty_array).len(), 0);
- assert_eq!(FixedSizeArray::as_mut_slice(&mut empty_zero_sized).len(), 0);
-}
-
#[test]
fn array_from_ref() {
let value: String = "Hello World!".into();
#![feature(duration_zero)]
#![feature(exact_size_is_empty)]
#![feature(extern_types)]
-#![feature(fixed_size_array)]
#![feature(flt2dec)]
#![feature(fmt_internals)]
#![feature(hashmap_internals)]
panic_unwind = { path = "../panic_unwind", optional = true }
panic_abort = { path = "../panic_abort" }
core = { path = "../core" }
-libc = { version = "0.2.88", default-features = false, features = ['rustc-dep-of-std'] }
+libc = { version = "0.2.93", default-features = false, features = ['rustc-dep-of-std'] }
compiler_builtins = { version = "0.1.39" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
/// ```no_run
/// use std::fs;
/// use std::net::SocketAddr;
+/// use std::error::Error;
///
-/// fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
+/// fn main() -> Result<(), Box<dyn Error>> {
/// let foo: SocketAddr = fs::read_to_string("address.txt")?.parse()?;
/// Ok(())
/// }
feature(slice_index_methods, coerce_unsized, sgx_platform)
)]
#![deny(rustc::existing_doc_keyword)]
-#![cfg_attr(all(test, target_vendor = "fortanix", target_env = "sgx"), feature(fixed_size_array))]
// std is implemented with unstable features, many of which are internal
// compiler details that will never be stable
// NB: the following list is sorted to minimize merge conflicts.
use rustc_errors::emitter::{Emitter, EmitterWriter};
use rustc_errors::json::JsonEmitter;
use rustc_feature::UnstableFeatures;
-use rustc_hir::def::{Namespace::TypeNS, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def::Res;
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
use rustc_hir::HirId;
use rustc_hir::{
intravisit::{self, NestedVisitorMap, Visitor},
let (krate, resolver, _) = &*parts;
let resolver = resolver.borrow().clone();
- // Letting the resolver escape at the end of the function leads to inconsistencies between the
- // crates the TyCtxt sees and the resolver sees (because the resolver could load more crates
- // after escaping). Hopefully `IntraLinkCrateLoader` gets all the crates we need ...
- struct IntraLinkCrateLoader {
- current_mod: DefId,
- resolver: Rc<RefCell<interface::BoxedResolver>>,
- }
- impl ast::visit::Visitor<'_> for IntraLinkCrateLoader {
- fn visit_attribute(&mut self, attr: &ast::Attribute) {
- use crate::html::markdown::{markdown_links, MarkdownLink};
- use crate::passes::collect_intra_doc_links::Disambiguator;
-
- if let Some(doc) = attr.doc_str() {
- for MarkdownLink { link, .. } in markdown_links(&doc.as_str()) {
- // FIXME: this misses a *lot* of the preprocessing done in collect_intra_doc_links
- // I think most of it shouldn't be necessary since we only need the crate prefix?
- let path_str = match Disambiguator::from_str(&link) {
- Ok(x) => x.map_or(link.as_str(), |(_, p)| p),
- Err(_) => continue,
- };
- self.resolver.borrow_mut().access(|resolver| {
- let _ = resolver.resolve_str_path_error(
- attr.span,
- path_str,
- TypeNS,
- self.current_mod,
- );
- });
- }
- }
- ast::visit::walk_attribute(self, attr);
- }
-
- fn visit_item(&mut self, item: &ast::Item) {
- use rustc_ast_lowering::ResolverAstLowering;
-
- if let ast::ItemKind::Mod(..) = item.kind {
- let new_mod =
- self.resolver.borrow_mut().access(|resolver| resolver.local_def_id(item.id));
- let old_mod = mem::replace(&mut self.current_mod, new_mod.to_def_id());
- ast::visit::walk_item(self, item);
- self.current_mod = old_mod;
- } else {
- ast::visit::walk_item(self, item);
- }
- }
- }
- let crate_id = LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id();
- let mut loader = IntraLinkCrateLoader { current_mod: crate_id, resolver };
+ let mut loader = crate::passes::collect_intra_doc_links::IntraLinkCrateLoader::new(resolver);
ast::visit::walk_crate(&mut loader, krate);
loader.resolver
use super::span_of_attrs;
+mod early;
+crate use early::IntraLinkCrateLoader;
+
crate const COLLECT_INTRA_DOC_LINKS: Pass = Pass {
name: "collect-intra-doc-links",
run: collect_intra_doc_links,
description: "resolves intra-doc links",
};
-crate fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
+fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
LinkCollector {
cx,
mod_ids: Vec::new(),
}
}
+enum PreprocessingError<'a> {
+ Anchor(AnchorFailure),
+ Disambiguator(Range<usize>, String),
+ Resolution(ResolutionFailure<'a>, String, Option<Disambiguator>),
+}
+
+impl From<AnchorFailure> for PreprocessingError<'_> {
+ fn from(err: AnchorFailure) -> Self {
+ Self::Anchor(err)
+ }
+}
+
+struct PreprocessingInfo {
+ path_str: String,
+ disambiguator: Option<Disambiguator>,
+ extra_fragment: Option<String>,
+ link_text: String,
+}
+
+/// Returns:
+/// - `None` if the link should be ignored.
+/// - `Some(Err)` if the link should emit an error
+/// - `Some(Ok)` if the link is valid
+///
+/// `link_buffer` is needed for lifetime reasons; it will always be overwritten and the contents ignored.
+fn preprocess_link<'a>(
+ ori_link: &'a MarkdownLink,
+) -> Option<Result<PreprocessingInfo, PreprocessingError<'a>>> {
+ // [] is mostly likely not supposed to be a link
+ if ori_link.link.is_empty() {
+ return None;
+ }
+
+ // Bail early for real links.
+ if ori_link.link.contains('/') {
+ return None;
+ }
+
+ let stripped = ori_link.link.replace("`", "");
+ let mut parts = stripped.split('#');
+
+ let link = parts.next().unwrap();
+ if link.trim().is_empty() {
+ // This is an anchor to an element of the current page, nothing to do in here!
+ return None;
+ }
+ let extra_fragment = parts.next();
+ if parts.next().is_some() {
+ // A valid link can't have multiple #'s
+ return Some(Err(AnchorFailure::MultipleAnchors.into()));
+ }
+
+ // Parse and strip the disambiguator from the link, if present.
+ let (path_str, disambiguator) = match Disambiguator::from_str(&link) {
+ Ok(Some((d, path))) => (path.trim(), Some(d)),
+ Ok(None) => (link.trim(), None),
+ Err((err_msg, relative_range)) => {
+ // Only report error if we would not have ignored this link. See issue #83859.
+ if !should_ignore_link_with_disambiguators(link) {
+ let no_backticks_range = range_between_backticks(&ori_link);
+ let disambiguator_range = (no_backticks_range.start + relative_range.start)
+ ..(no_backticks_range.start + relative_range.end);
+ return Some(Err(PreprocessingError::Disambiguator(disambiguator_range, err_msg)));
+ } else {
+ return None;
+ }
+ }
+ };
+
+ if should_ignore_link(path_str) {
+ return None;
+ }
+
+ // We stripped `()` and `!` when parsing the disambiguator.
+ // Add them back to be displayed, but not prefix disambiguators.
+ let link_text =
+ disambiguator.map(|d| d.display_for(path_str)).unwrap_or_else(|| path_str.to_owned());
+
+ // Strip generics from the path.
+ let path_str = if path_str.contains(['<', '>'].as_slice()) {
+ match strip_generics_from_path(&path_str) {
+ Ok(path) => path,
+ Err(err_kind) => {
+ debug!("link has malformed generics: {}", path_str);
+ return Some(Err(PreprocessingError::Resolution(
+ err_kind,
+ path_str.to_owned(),
+ disambiguator,
+ )));
+ }
+ }
+ } else {
+ path_str.to_owned()
+ };
+
+ // Sanity check to make sure we don't have any angle brackets after stripping generics.
+ assert!(!path_str.contains(['<', '>'].as_slice()));
+
+ // The link is not an intra-doc link if it still contains spaces after stripping generics.
+ if path_str.contains(' ') {
+ return None;
+ }
+
+ Some(Ok(PreprocessingInfo {
+ path_str,
+ disambiguator,
+ extra_fragment: extra_fragment.map(String::from),
+ link_text,
+ }))
+}
+
impl LinkCollector<'_, '_> {
/// This is the entry point for resolving an intra-doc link.
///
) -> Option<ItemLink> {
trace!("considering link '{}'", ori_link.link);
- // Bail early for real links.
- if ori_link.link.contains('/') {
- return None;
- }
-
- // [] is mostly likely not supposed to be a link
- if ori_link.link.is_empty() {
- return None;
- }
-
let diag_info = DiagnosticInfo {
item,
dox,
link_range: ori_link.range.clone(),
};
- let link = ori_link.link.replace("`", "");
- let no_backticks_range = range_between_backticks(&ori_link);
- let parts = link.split('#').collect::<Vec<_>>();
- let (link, extra_fragment) = if parts.len() > 2 {
- // A valid link can't have multiple #'s
- anchor_failure(self.cx, diag_info, AnchorFailure::MultipleAnchors);
- return None;
- } else if parts.len() == 2 {
- if parts[0].trim().is_empty() {
- // This is an anchor to an element of the current page, nothing to do in here!
- return None;
- }
- (parts[0], Some(parts[1].to_owned()))
- } else {
- (parts[0], None)
- };
-
- // Parse and strip the disambiguator from the link, if present.
- let (mut path_str, disambiguator) = match Disambiguator::from_str(&link) {
- Ok(Some((d, path))) => (path.trim(), Some(d)),
- Ok(None) => (link.trim(), None),
- Err((err_msg, relative_range)) => {
- if !should_ignore_link_with_disambiguators(link) {
- // Only report error if we would not have ignored this link.
- // See issue #83859.
- let disambiguator_range = (no_backticks_range.start + relative_range.start)
- ..(no_backticks_range.start + relative_range.end);
- disambiguator_error(self.cx, diag_info, disambiguator_range, &err_msg);
+ let PreprocessingInfo { path_str, disambiguator, extra_fragment, link_text } =
+ match preprocess_link(&ori_link)? {
+ Ok(x) => x,
+ Err(err) => {
+ match err {
+ PreprocessingError::Anchor(err) => anchor_failure(self.cx, diag_info, err),
+ PreprocessingError::Disambiguator(range, msg) => {
+ disambiguator_error(self.cx, diag_info, range, &msg)
+ }
+ PreprocessingError::Resolution(err, path_str, disambiguator) => {
+ resolution_failure(
+ self,
+ diag_info,
+ &path_str,
+ disambiguator,
+ smallvec![err],
+ );
+ }
+ }
+ return None;
}
- return None;
- }
- };
-
- if should_ignore_link(path_str) {
- return None;
- }
-
- // We stripped `()` and `!` when parsing the disambiguator.
- // Add them back to be displayed, but not prefix disambiguators.
- let link_text =
- disambiguator.map(|d| d.display_for(path_str)).unwrap_or_else(|| path_str.to_owned());
+ };
+ let mut path_str = &*path_str;
// In order to correctly resolve intra-doc links we need to
// pick a base AST node to work from. If the documentation for
module_id = DefId { krate, index: CRATE_DEF_INDEX };
}
- // Strip generics from the path.
- let stripped_path_string;
- if path_str.contains(['<', '>'].as_slice()) {
- stripped_path_string = match strip_generics_from_path(path_str) {
- Ok(path) => path,
- Err(err_kind) => {
- debug!("link has malformed generics: {}", path_str);
- resolution_failure(
- self,
- diag_info,
- path_str,
- disambiguator,
- smallvec![err_kind],
- );
- return None;
- }
- };
- path_str = &stripped_path_string;
- }
- // Sanity check to make sure we don't have any angle brackets after stripping generics.
- assert!(!path_str.contains(['<', '>'].as_slice()));
-
- // The link is not an intra-doc link if it still contains spaces after stripping generics.
- if path_str.contains(' ') {
- return None;
- }
-
let (mut res, mut fragment) = self.resolve_with_disambiguator_cached(
ResolutionInfo {
module_id,
dis: disambiguator,
path_str: path_str.to_owned(),
- extra_fragment,
+ extra_fragment: extra_fragment.map(String::from),
},
diag_info.clone(), // this struct should really be Copy, but Range is not :(
matches!(ori_link.kind, LinkType::Reference | LinkType::Shortcut),
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
/// Disambiguators for a link.
-crate enum Disambiguator {
+enum Disambiguator {
/// `prim@`
///
/// This is buggy, see <https://github.com/rust-lang/rust/pull/77875#discussion_r503583103>
/// This returns `Ok(Some(...))` if a disambiguator was found,
/// `Ok(None)` if no disambiguator was found, or `Err(...)`
/// if there was a problem with the disambiguator.
- crate fn from_str(link: &str) -> Result<Option<(Self, &str)>, (String, Range<usize>)> {
+ fn from_str(link: &str) -> Result<Option<(Self, &str)>, (String, Range<usize>)> {
use Disambiguator::{Kind, Namespace as NS, Primitive};
if let Some(idx) = link.find('@') {
--- /dev/null
+use rustc_ast as ast;
+use rustc_hir::def::Namespace::TypeNS;
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
+use rustc_interface::interface;
+
+use std::cell::RefCell;
+use std::mem;
+use std::rc::Rc;
+
+// Letting the resolver escape at the end of the function leads to inconsistencies between the
+// crates the TyCtxt sees and the resolver sees (because the resolver could load more crates
+// after escaping). Hopefully `IntraLinkCrateLoader` gets all the crates we need ...
+crate struct IntraLinkCrateLoader {
+ current_mod: DefId,
+ crate resolver: Rc<RefCell<interface::BoxedResolver>>,
+}
+
+impl IntraLinkCrateLoader {
+ crate fn new(resolver: Rc<RefCell<interface::BoxedResolver>>) -> Self {
+ let crate_id = LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id();
+ Self { current_mod: crate_id, resolver }
+ }
+}
+
+impl ast::visit::Visitor<'_> for IntraLinkCrateLoader {
+ fn visit_attribute(&mut self, attr: &ast::Attribute) {
+ use crate::html::markdown::markdown_links;
+ use crate::passes::collect_intra_doc_links::preprocess_link;
+
+ if let Some(doc) = attr.doc_str() {
+ for link in markdown_links(&doc.as_str()) {
+ let path_str = if let Some(Ok(x)) = preprocess_link(&link) {
+ x.path_str
+ } else {
+ continue;
+ };
+ self.resolver.borrow_mut().access(|resolver| {
+ let _ = resolver.resolve_str_path_error(
+ attr.span,
+ &path_str,
+ TypeNS,
+ self.current_mod,
+ );
+ });
+ }
+ }
+ ast::visit::walk_attribute(self, attr);
+ }
+
+ fn visit_item(&mut self, item: &ast::Item) {
+ use rustc_ast_lowering::ResolverAstLowering;
+
+ if let ast::ItemKind::Mod(..) = item.kind {
+ let new_mod =
+ self.resolver.borrow_mut().access(|resolver| resolver.local_def_id(item.id));
+ let old_mod = mem::replace(&mut self.current_mod, new_mod.to_def_id());
+ ast::visit::walk_item(self, item);
+ self.current_mod = old_mod;
+ } else {
+ ast::visit::walk_item(self, item);
+ }
+ }
+}
--- /dev/null
+// run-rustfix
+
+#![deny(rustdoc::bare_urls)]
+
+/// <https://somewhere.com>
+//~^ ERROR this URL is not a hyperlink
+/// <https://somewhere.com/a>
+//~^ ERROR this URL is not a hyperlink
+/// <https://www.somewhere.com>
+//~^ ERROR this URL is not a hyperlink
+/// <https://www.somewhere.com/a>
+//~^ ERROR this URL is not a hyperlink
+/// <https://subdomain.example.com>
+//~^ ERROR not a hyperlink
+/// <https://somewhere.com?>
+//~^ ERROR this URL is not a hyperlink
+/// <https://somewhere.com/a?>
+//~^ ERROR this URL is not a hyperlink
+/// <https://somewhere.com?hello=12>
+//~^ ERROR this URL is not a hyperlink
+/// <https://somewhere.com/a?hello=12>
+//~^ ERROR this URL is not a hyperlink
+/// <https://example.com?hello=12#xyz>
+//~^ ERROR this URL is not a hyperlink
+/// <https://example.com/a?hello=12#xyz>
+//~^ ERROR this URL is not a hyperlink
+/// <https://example.com#xyz>
+//~^ ERROR this URL is not a hyperlink
+/// <https://example.com/a#xyz>
+//~^ ERROR this URL is not a hyperlink
+/// <https://somewhere.com?hello=12&bye=11>
+//~^ ERROR this URL is not a hyperlink
+/// <https://somewhere.com/a?hello=12&bye=11>
+//~^ ERROR this URL is not a hyperlink
+/// <https://somewhere.com?hello=12&bye=11#xyz>
+//~^ ERROR this URL is not a hyperlink
+/// hey! <https://somewhere.com/a?hello=12&bye=11#xyz>
+//~^ ERROR this URL is not a hyperlink
+pub fn c() {}
+
+/// <https://somewhere.com>
+/// [a](http://a.com)
+/// [b]
+///
+/// [b]: http://b.com
+///
+/// ```
+/// This link should not be linted: http://example.com
+///
+/// Nor this one: <http://example.com> or this one: [x](http://example.com)
+/// ```
+///
+/// [should_not.lint](should_not.lint)
+pub fn everything_is_fine_here() {}
+
+#[allow(rustdoc::bare_urls)]
+pub mod foo {
+ /// https://somewhere.com/a?hello=12&bye=11#xyz
+ pub fn bar() {}
+}
--- /dev/null
+// run-rustfix
+
+#![deny(rustdoc::bare_urls)]
+
+/// https://somewhere.com
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com/a
+//~^ ERROR this URL is not a hyperlink
+/// https://www.somewhere.com
+//~^ ERROR this URL is not a hyperlink
+/// https://www.somewhere.com/a
+//~^ ERROR this URL is not a hyperlink
+/// https://subdomain.example.com
+//~^ ERROR not a hyperlink
+/// https://somewhere.com?
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com/a?
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com?hello=12
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com/a?hello=12
+//~^ ERROR this URL is not a hyperlink
+/// https://example.com?hello=12#xyz
+//~^ ERROR this URL is not a hyperlink
+/// https://example.com/a?hello=12#xyz
+//~^ ERROR this URL is not a hyperlink
+/// https://example.com#xyz
+//~^ ERROR this URL is not a hyperlink
+/// https://example.com/a#xyz
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com?hello=12&bye=11
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com/a?hello=12&bye=11
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com?hello=12&bye=11#xyz
+//~^ ERROR this URL is not a hyperlink
+/// hey! https://somewhere.com/a?hello=12&bye=11#xyz
+//~^ ERROR this URL is not a hyperlink
+pub fn c() {}
+
+/// <https://somewhere.com>
+/// [a](http://a.com)
+/// [b]
+///
+/// [b]: http://b.com
+///
+/// ```
+/// This link should not be linted: http://example.com
+///
+/// Nor this one: <http://example.com> or this one: [x](http://example.com)
+/// ```
+///
+/// [should_not.lint](should_not.lint)
+pub fn everything_is_fine_here() {}
+
+#[allow(rustdoc::bare_urls)]
+pub mod foo {
+ /// https://somewhere.com/a?hello=12&bye=11#xyz
+ pub fn bar() {}
+}
--- /dev/null
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:5:5
+ |
+LL | /// https://somewhere.com
+ | ^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com>`
+ |
+note: the lint level is defined here
+ --> $DIR/bare-urls.rs:3:9
+ |
+LL | #![deny(rustdoc::bare_urls)]
+ | ^^^^^^^^^^^^^^^^^^
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:7:5
+ |
+LL | /// https://somewhere.com/a
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a>`
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:9:5
+ |
+LL | /// https://www.somewhere.com
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com>`
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:11:5
+ |
+LL | /// https://www.somewhere.com/a
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com/a>`
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:13:5
+ |
+LL | /// https://subdomain.example.com
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://subdomain.example.com>`
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:15:5
+ |
+LL | /// https://somewhere.com?
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?>`
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:17:5
+ |
+LL | /// https://somewhere.com/a?
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?>`
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:19:5
+ |
+LL | /// https://somewhere.com?hello=12
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12>`
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:21:5
+ |
+LL | /// https://somewhere.com/a?hello=12
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12>`
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:23:5
+ |
+LL | /// https://example.com?hello=12#xyz
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com?hello=12#xyz>`
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:25:5
+ |
+LL | /// https://example.com/a?hello=12#xyz
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a?hello=12#xyz>`
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:27:5
+ |
+LL | /// https://example.com#xyz
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com#xyz>`
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:29:5
+ |
+LL | /// https://example.com/a#xyz
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a#xyz>`
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:31:5
+ |
+LL | /// https://somewhere.com?hello=12&bye=11
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11>`
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:33:5
+ |
+LL | /// https://somewhere.com/a?hello=12&bye=11
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11>`
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:35:5
+ |
+LL | /// https://somewhere.com?hello=12&bye=11#xyz
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11#xyz>`
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:37:10
+ |
+LL | /// hey! https://somewhere.com/a?hello=12&bye=11#xyz
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11#xyz>`
+
+error: aborting due to 17 previous errors
+
+++ /dev/null
-#![deny(rustdoc::bare_urls)]
-
-/// https://somewhere.com
-//~^ ERROR this URL is not a hyperlink
-/// https://somewhere.com/a
-//~^ ERROR this URL is not a hyperlink
-/// https://www.somewhere.com
-//~^ ERROR this URL is not a hyperlink
-/// https://www.somewhere.com/a
-//~^ ERROR this URL is not a hyperlink
-/// https://subdomain.example.com
-//~^ ERROR not a hyperlink
-/// https://somewhere.com?
-//~^ ERROR this URL is not a hyperlink
-/// https://somewhere.com/a?
-//~^ ERROR this URL is not a hyperlink
-/// https://somewhere.com?hello=12
-//~^ ERROR this URL is not a hyperlink
-/// https://somewhere.com/a?hello=12
-//~^ ERROR this URL is not a hyperlink
-/// https://example.com?hello=12#xyz
-//~^ ERROR this URL is not a hyperlink
-/// https://example.com/a?hello=12#xyz
-//~^ ERROR this URL is not a hyperlink
-/// https://example.com#xyz
-//~^ ERROR this URL is not a hyperlink
-/// https://example.com/a#xyz
-//~^ ERROR this URL is not a hyperlink
-/// https://somewhere.com?hello=12&bye=11
-//~^ ERROR this URL is not a hyperlink
-/// https://somewhere.com/a?hello=12&bye=11
-//~^ ERROR this URL is not a hyperlink
-/// https://somewhere.com?hello=12&bye=11#xyz
-//~^ ERROR this URL is not a hyperlink
-/// hey! https://somewhere.com/a?hello=12&bye=11#xyz
-//~^ ERROR this URL is not a hyperlink
-pub fn c() {}
-
-/// <https://somewhere.com>
-/// [a](http://a.com)
-/// [b]
-///
-/// [b]: http://b.com
-///
-/// ```
-/// This link should not be linted: http://example.com
-///
-/// Nor this one: <http://example.com> or this one: [x](http://example.com)
-/// ```
-///
-/// [should_not.lint](should_not.lint)
-pub fn everything_is_fine_here() {}
-
-#[allow(rustdoc::bare_urls)]
-pub mod foo {
- /// https://somewhere.com/a?hello=12&bye=11#xyz
- pub fn bar() {}
-}
+++ /dev/null
-error: this URL is not a hyperlink
- --> $DIR/url-improvements.rs:3:5
- |
-LL | /// https://somewhere.com
- | ^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com>`
- |
-note: the lint level is defined here
- --> $DIR/url-improvements.rs:1:9
- |
-LL | #![deny(rustdoc::bare_urls)]
- | ^^^^^^^^^^^^^^^^^^
-
-error: this URL is not a hyperlink
- --> $DIR/url-improvements.rs:5:5
- |
-LL | /// https://somewhere.com/a
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a>`
-
-error: this URL is not a hyperlink
- --> $DIR/url-improvements.rs:7:5
- |
-LL | /// https://www.somewhere.com
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com>`
-
-error: this URL is not a hyperlink
- --> $DIR/url-improvements.rs:9:5
- |
-LL | /// https://www.somewhere.com/a
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com/a>`
-
-error: this URL is not a hyperlink
- --> $DIR/url-improvements.rs:11:5
- |
-LL | /// https://subdomain.example.com
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://subdomain.example.com>`
-
-error: this URL is not a hyperlink
- --> $DIR/url-improvements.rs:13:5
- |
-LL | /// https://somewhere.com?
- | ^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?>`
-
-error: this URL is not a hyperlink
- --> $DIR/url-improvements.rs:15:5
- |
-LL | /// https://somewhere.com/a?
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?>`
-
-error: this URL is not a hyperlink
- --> $DIR/url-improvements.rs:17:5
- |
-LL | /// https://somewhere.com?hello=12
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12>`
-
-error: this URL is not a hyperlink
- --> $DIR/url-improvements.rs:19:5
- |
-LL | /// https://somewhere.com/a?hello=12
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12>`
-
-error: this URL is not a hyperlink
- --> $DIR/url-improvements.rs:21:5
- |
-LL | /// https://example.com?hello=12#xyz
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com?hello=12#xyz>`
-
-error: this URL is not a hyperlink
- --> $DIR/url-improvements.rs:23:5
- |
-LL | /// https://example.com/a?hello=12#xyz
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a?hello=12#xyz>`
-
-error: this URL is not a hyperlink
- --> $DIR/url-improvements.rs:25:5
- |
-LL | /// https://example.com#xyz
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com#xyz>`
-
-error: this URL is not a hyperlink
- --> $DIR/url-improvements.rs:27:5
- |
-LL | /// https://example.com/a#xyz
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a#xyz>`
-
-error: this URL is not a hyperlink
- --> $DIR/url-improvements.rs:29:5
- |
-LL | /// https://somewhere.com?hello=12&bye=11
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11>`
-
-error: this URL is not a hyperlink
- --> $DIR/url-improvements.rs:31:5
- |
-LL | /// https://somewhere.com/a?hello=12&bye=11
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11>`
-
-error: this URL is not a hyperlink
- --> $DIR/url-improvements.rs:33:5
- |
-LL | /// https://somewhere.com?hello=12&bye=11#xyz
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11#xyz>`
-
-error: this URL is not a hyperlink
- --> $DIR/url-improvements.rs:35:10
- |
-LL | /// hey! https://somewhere.com/a?hello=12&bye=11#xyz
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11#xyz>`
-
-error: aborting due to 17 previous errors
-
--- /dev/null
+// intentionally empty
--- /dev/null
+// intentionally empty
+// This test is just a little cursed.
// aux-build:issue-66159-1.rs
// aux-crate:priv:issue_66159_1=issue-66159-1.rs
+// aux-build:empty.rs
+// aux-crate:priv:empty=empty.rs
+// aux-build:empty2.rs
+// aux-crate:priv:empty2=empty2.rs
// build-aux-docs
-// compile-flags:-Z unstable-options
+// compile-flags:-Z unstable-options --edition 2018
// @has extern_crate_only_used_in_link/index.html
// @has - '//a[@href="../issue_66159_1/struct.Something.html"]' 'issue_66159_1::Something'
//! [issue_66159_1::Something]
+
+// @has - '//a[@href="../empty/index.html"]' 'empty'
+//! [`empty`]
+
+// @has - '//a[@href="../empty2/index.html"]' 'empty2'
+//! [empty2<x>]
| -------- type in trait
...
LL | fn make() -> u8 { 0 }
- | ^^ expected associated type, found `u8`
+ | ^^
+ | |
+ | expected associated type, found `u8`
+ | help: change the output type to match the trait: `<A<T> as Tr>::Ty`
|
= note: expected fn pointer `fn() -> <A<T> as Tr>::Ty`
found fn pointer `fn() -> u8`
| ----------------------- expected this associated type
LL |
LL | fn make() -> bool { true }
- | ^^^^ expected associated type, found `bool`
+ | ^^^^
+ | |
+ | expected associated type, found `bool`
+ | help: change the output type to match the trait: `<B<T> as Tr>::Ty`
|
= note: expected fn pointer `fn() -> <B<T> as Tr>::Ty`
found fn pointer `fn() -> bool`
--- /dev/null
+use std::future::Future;
+use std::task::{Context, Poll};
+
+fn main() {}
+
+struct MyFuture {}
+
+impl Future for MyFuture {
+ type Output = ();
+ fn poll(self, _: &mut Context<'_>) -> Poll<()> {
+ //~^ ERROR method `poll` has an incompatible type for trait
+ todo!()
+ }
+}
+
+trait T {
+ fn foo(self);
+ fn bar(self) -> Option<()>;
+}
+
+impl T for MyFuture {
+ fn foo(self: Box<Self>) {}
+ //~^ ERROR method `foo` has an incompatible type for trait
+ fn bar(self) {}
+ //~^ ERROR method `bar` has an incompatible type for trait
+}
--- /dev/null
+error[E0053]: method `poll` has an incompatible type for trait
+ --> $DIR/bad-self-type.rs:10:13
+ |
+LL | fn poll(self, _: &mut Context<'_>) -> Poll<()> {
+ | ^^^^
+ | |
+ | expected struct `Pin`, found struct `MyFuture`
+ | help: change the self-receiver type to match the trait: `self: Pin<&mut MyFuture>`
+ |
+ = note: expected fn pointer `fn(Pin<&mut MyFuture>, &mut Context<'_>) -> Poll<_>`
+ found fn pointer `fn(MyFuture, &mut Context<'_>) -> Poll<_>`
+
+error[E0053]: method `foo` has an incompatible type for trait
+ --> $DIR/bad-self-type.rs:22:18
+ |
+LL | fn foo(self);
+ | ---- type in trait
+...
+LL | fn foo(self: Box<Self>) {}
+ | ------^^^^^^^^^
+ | | |
+ | | expected struct `MyFuture`, found struct `Box`
+ | help: change the self-receiver type to match the trait: `self`
+ |
+ = note: expected fn pointer `fn(MyFuture)`
+ found fn pointer `fn(Box<MyFuture>)`
+
+error[E0053]: method `bar` has an incompatible type for trait
+ --> $DIR/bad-self-type.rs:24:18
+ |
+LL | fn bar(self) -> Option<()>;
+ | ---------- type in trait
+...
+LL | fn bar(self) {}
+ | ^ expected enum `Option`, found `()`
+ |
+ = note: expected fn pointer `fn(MyFuture) -> Option<()>`
+ found fn pointer `fn(MyFuture)`
+help: change the output type to match the trait
+ |
+LL | fn bar(self) -> Option<()> {}
+ | ^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0053`.
| - type in trait
...
LL | fn b<F:Clone,G>(&self, _x: G) -> G { panic!() }
- | - - ^ expected type parameter `F`, found type parameter `G`
- | | |
+ | - - ^
+ | | | |
+ | | | expected type parameter `F`, found type parameter `G`
+ | | | help: change the parameter type to match the trait: `F`
| | found type parameter
| expected type parameter
|
| -- type in trait
...
LL | fn foo<B: Debug>(&self, a: &impl Debug, b: &B) { }
- | - ^^^^^^^^^^^ expected type parameter `B`, found type parameter `impl Debug`
- | |
+ | - ^^^^^^^^^^^
+ | | |
+ | | expected type parameter `B`, found type parameter `impl Debug`
+ | | help: change the parameter type to match the trait: `&B`
| expected type parameter
|
= note: expected fn pointer `fn(&(), &B, &impl Debug)`
error[E0053]: method `fmt` has an incompatible type for trait
- --> $DIR/trait_type.rs:7:4
+ --> $DIR/trait_type.rs:7:21
|
LL | fn fmt(&self, x: &str) -> () { }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability
+ | ^^^^
+ | |
+ | types differ in mutability
+ | help: change the parameter type to match the trait: `&mut Formatter<'_>`
|
= note: expected fn pointer `fn(&MyType, &mut Formatter<'_>) -> Result<(), std::fmt::Error>`
found fn pointer `fn(&MyType, &str)`
| ^^^^^^^^
| |
| types differ in mutability
- | help: consider changing the mutability to match the trait: `&mut dyn Foo`
+ | help: change the parameter type to match the trait: `&mut dyn Foo`
|
= note: expected fn pointer `fn(&mut Baz, &mut dyn Foo)`
found fn pointer `fn(&mut Baz, &dyn Foo)`
error[E0053]: method `call` has an incompatible type for trait
- --> $DIR/issue-20225.rs:6:3
+ --> $DIR/issue-20225.rs:6:43
|
LL | impl<'a, T> Fn<(&'a T,)> for Foo {
| - this type parameter
LL | extern "rust-call" fn call(&self, (_,): (T,)) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&T`, found type parameter `T`
+ | ^^^^
+ | |
+ | expected `&T`, found type parameter `T`
+ | help: change the parameter type to match the trait: `(&'a T,)`
|
= note: expected fn pointer `extern "rust-call" fn(&Foo, (&'a T,))`
found fn pointer `extern "rust-call" fn(&Foo, (T,))`
error[E0053]: method `call_mut` has an incompatible type for trait
- --> $DIR/issue-20225.rs:11:3
+ --> $DIR/issue-20225.rs:11:51
|
LL | impl<'a, T> FnMut<(&'a T,)> for Foo {
| - this type parameter
LL | extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&T`, found type parameter `T`
+ | ^^^^
+ | |
+ | expected `&T`, found type parameter `T`
+ | help: change the parameter type to match the trait: `(&'a T,)`
|
= note: expected fn pointer `extern "rust-call" fn(&mut Foo, (&'a T,))`
found fn pointer `extern "rust-call" fn(&mut Foo, (T,))`
error[E0053]: method `call_once` has an incompatible type for trait
- --> $DIR/issue-20225.rs:18:3
+ --> $DIR/issue-20225.rs:18:47
|
LL | impl<'a, T> FnOnce<(&'a T,)> for Foo {
| - this type parameter
...
LL | extern "rust-call" fn call_once(self, (_,): (T,)) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&T`, found type parameter `T`
+ | ^^^^
+ | |
+ | expected `&T`, found type parameter `T`
+ | help: change the parameter type to match the trait: `(&'a T,)`
|
= note: expected fn pointer `extern "rust-call" fn(Foo, (&'a T,))`
found fn pointer `extern "rust-call" fn(Foo, (T,))`
error[E0053]: method `next` has an incompatible type for trait
- --> $DIR/issue-21332.rs:5:5
+ --> $DIR/issue-21332.rs:5:27
|
LL | fn next(&mut self) -> Result<i32, i32> { Ok(7) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Option`, found enum `Result`
+ | ^^^^^^^^^^^^^^^^
+ | |
+ | expected enum `Option`, found enum `Result`
+ | help: change the output type to match the trait: `Option<i32>`
|
= note: expected fn pointer `fn(&mut S) -> Option<i32>`
found fn pointer `fn(&mut S) -> Result<i32, i32>`
| ------------ type in trait
...
LL | fn foo(_: fn(u16) -> ()) {}
- | ^^^^^^^^^^^^^ expected `u8`, found `u16`
+ | ^^^^^^^^^^^^^
+ | |
+ | expected `u8`, found `u16`
+ | help: change the parameter type to match the trait: `fn(u8)`
|
= note: expected fn pointer `fn(fn(u8))`
found fn pointer `fn(fn(u16))`
| ---------- type in trait
...
LL | fn bar(_: Option<u16>) {}
- | ^^^^^^^^^^^ expected `u8`, found `u16`
+ | ^^^^^^^^^^^
+ | |
+ | expected `u8`, found `u16`
+ | help: change the parameter type to match the trait: `Option<u8>`
|
= note: expected fn pointer `fn(Option<u8>)`
found fn pointer `fn(Option<u16>)`
| --------- type in trait
...
LL | fn baz(_: (u16, u16)) {}
- | ^^^^^^^^^^ expected `u8`, found `u16`
+ | ^^^^^^^^^^
+ | |
+ | expected `u8`, found `u16`
+ | help: change the parameter type to match the trait: `(u8, u16)`
|
= note: expected fn pointer `fn((u8, _))`
found fn pointer `fn((u16, _))`
| -- type in trait
...
LL | fn qux() -> u16 { 5u16 }
- | ^^^ expected `u8`, found `u16`
+ | ^^^
+ | |
+ | expected `u8`, found `u16`
+ | help: change the output type to match the trait: `u8`
|
= note: expected fn pointer `fn() -> u8`
found fn pointer `fn() -> u16`
| --- type in trait
...
LL | fn foo(x: i16) { }
- | ^^^ expected `u16`, found `i16`
+ | ^^^
+ | |
+ | expected `u16`, found `i16`
+ | help: change the parameter type to match the trait: `u16`
|
= note: expected fn pointer `fn(u16)`
found fn pointer `fn(i16)`
| ^^^^^^^^^
| |
| types differ in mutability
- | help: consider changing the mutability to match the trait: `&self`
+ | help: change the self-receiver type to match the trait: `self: &Bar`
|
= note: expected fn pointer `fn(&Bar)`
found fn pointer `fn(&mut Bar)`
| --- type in trait
...
LL | fn foo(x: i16) { }
- | ^^^ expected `u16`, found `i16`
+ | ^^^
+ | |
+ | expected `u16`, found `i16`
+ | help: change the parameter type to match the trait: `u16`
|
= note: expected fn pointer `fn(u16)`
found fn pointer `fn(i16)`
| ^^^^
| |
| types differ in mutability
- | help: consider changing the mutability to match the trait: `&mut Bar`
+ | help: change the parameter type to match the trait: `&mut Bar`
|
= note: expected fn pointer `fn(&mut Bar, &mut Bar)`
found fn pointer `fn(&mut Bar, &Bar)`
--- /dev/null
+// Confusing diagnostic when using variable as a type:
+//
+// Previous warnings indicate Foo is not used, when in fact it is
+// used improperly as a variable or constant. New warning points
+// out user may be trying to use variable as a type. Test demonstrates
+// cases for both local variable and const.
+
+fn main() {
+ let Baz: &str = "";
+
+ println!("{}", Baz::Bar); //~ ERROR: failed to resolve: use of undeclared type `Baz`
+}
+
+#[allow(non_upper_case_globals)]
+pub const Foo: &str = "";
+
+mod submod {
+ use super::Foo;
+ fn function() {
+ println!("{}", Foo::Bar); //~ ERROR: failed to resolve: use of undeclared type `Foo`
+ }
+}
--- /dev/null
+error[E0433]: failed to resolve: use of undeclared type `Baz`
+ --> $DIR/issue-81508.rs:11:20
+ |
+LL | let Baz: &str = "";
+ | --- help: `Baz` is defined here, but is not a type
+LL |
+LL | println!("{}", Baz::Bar);
+ | ^^^ use of undeclared type `Baz`
+
+error[E0433]: failed to resolve: use of undeclared type `Foo`
+ --> $DIR/issue-81508.rs:20:24
+ |
+LL | use super::Foo;
+ | ---------- help: `Foo` is defined here, but is not a type
+LL | fn function() {
+LL | println!("{}", Foo::Bar);
+ | ^^^ use of undeclared type `Foo`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
error[E0053]: method `mul` has an incompatible type for trait
- --> $DIR/wrong-mul-method-signature.rs:16:5
+ --> $DIR/wrong-mul-method-signature.rs:16:21
|
LL | fn mul(self, s: &f64) -> Vec1 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `f64`, found `&f64`
+ | ^^^^
+ | |
+ | expected `f64`, found `&f64`
+ | help: change the parameter type to match the trait: `f64`
|
= note: expected fn pointer `fn(Vec1, f64) -> Vec1`
found fn pointer `fn(Vec1, &f64) -> Vec1`
error[E0053]: method `mul` has an incompatible type for trait
- --> $DIR/wrong-mul-method-signature.rs:33:5
+ --> $DIR/wrong-mul-method-signature.rs:33:21
|
LL | fn mul(self, s: f64) -> Vec2 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Vec2`, found `f64`
+ | ^^^
+ | |
+ | expected struct `Vec2`, found `f64`
+ | help: change the parameter type to match the trait: `Vec2`
|
= note: expected fn pointer `fn(Vec2, Vec2) -> f64`
found fn pointer `fn(Vec2, f64) -> Vec2`
error[E0053]: method `mul` has an incompatible type for trait
- --> $DIR/wrong-mul-method-signature.rs:52:5
+ --> $DIR/wrong-mul-method-signature.rs:52:29
|
LL | fn mul(self, s: f64) -> f64 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `f64`
+ | ^^^
+ | |
+ | expected `i32`, found `f64`
+ | help: change the output type to match the trait: `i32`
|
= note: expected fn pointer `fn(Vec3, _) -> i32`
found fn pointer `fn(Vec3, _) -> f64`