use syntax::tokenstream::{TokenStream, TokenTree, Delimited};
use syntax::util::lev_distance::find_best_match_for_name;
use syntax_pos::{Span, DUMMY_SP};
+ use errors::Applicability;
use std::cell::Cell;
use std::mem;
use rustc_data_structures::sync::Lrc;
+crate struct FromPrelude(bool);
+crate struct FromExpansion(bool);
+
#[derive(Clone)]
pub struct InvocationData<'a> {
pub module: Cell<Module<'a>>,
pub span: Span,
}
+impl<'a> LegacyBinding<'a> {
+ fn def(&self) -> Def {
+ Def::Macro(self.def_id, MacroKind::Bang)
+ }
+}
+
pub struct ProcMacError {
crate_name: Symbol,
name: Symbol,
warn_msg: &'static str,
}
-#[derive(Copy, Clone)]
-pub enum MacroBinding<'a> {
- Legacy(&'a LegacyBinding<'a>),
- Global(&'a NameBinding<'a>),
- Modern(&'a NameBinding<'a>),
-}
-
-impl<'a> MacroBinding<'a> {
- pub fn span(self) -> Span {
- match self {
- MacroBinding::Legacy(binding) => binding.span,
- MacroBinding::Global(binding) | MacroBinding::Modern(binding) => binding.span,
- }
- }
-
- pub fn binding(self) -> &'a NameBinding<'a> {
- match self {
- MacroBinding::Global(binding) | MacroBinding::Modern(binding) => binding,
- MacroBinding::Legacy(_) => panic!("unexpected MacroBinding::Legacy"),
- }
- }
-
- pub fn def_ignoring_ambiguity(self) -> Def {
- match self {
- MacroBinding::Legacy(binding) => Def::Macro(binding.def_id, MacroKind::Bang),
- MacroBinding::Global(binding) | MacroBinding::Modern(binding) =>
- binding.def_ignoring_ambiguity(),
- }
- }
-}
-
impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
fn next_node_id(&mut self) -> ast::NodeId {
self.session.next_node_id()
None
}
- fn resolve_invoc(&mut self, invoc: &Invocation, scope: Mark, force: bool)
- -> Result<Option<Lrc<SyntaxExtension>>, Determinacy> {
- let def = match invoc.kind {
- InvocationKind::Attr { attr: None, .. } => return Ok(None),
- _ => self.resolve_invoc_to_def(invoc, scope, force)?,
+ fn resolve_macro_invocation(&mut self, invoc: &Invocation, scope: Mark, force: bool)
+ -> Result<Option<Lrc<SyntaxExtension>>, Determinacy> {
+ let (path, kind, derives_in_scope) = match invoc.kind {
+ InvocationKind::Attr { attr: None, .. } =>
+ return Ok(None),
+ InvocationKind::Attr { attr: Some(ref attr), ref traits, .. } =>
+ (&attr.path, MacroKind::Attr, &traits[..]),
+ InvocationKind::Bang { ref mac, .. } =>
+ (&mac.node.path, MacroKind::Bang, &[][..]),
+ InvocationKind::Derive { ref path, .. } =>
+ (path, MacroKind::Derive, &[][..]),
};
- if let Def::Macro(_, MacroKind::ProcMacroStub) = def {
- self.report_proc_macro_stub(invoc.span());
- return Err(Determinacy::Determined);
- } else if let Def::NonMacroAttr(attr_kind) = def {
- // Note that not only attributes, but anything in macro namespace can result in a
- // `Def::NonMacroAttr` definition (e.g. `inline!()`), so we must report the error
- // below for these cases.
- let is_attr_invoc =
- if let InvocationKind::Attr { .. } = invoc.kind { true } else { false };
- let path = invoc.path().expect("no path for non-macro attr");
- match attr_kind {
- NonMacroAttrKind::Tool | NonMacroAttrKind::DeriveHelper |
- NonMacroAttrKind::Custom if is_attr_invoc => {
- let features = self.session.features_untracked();
- if attr_kind == NonMacroAttrKind::Tool &&
- !features.tool_attributes {
- feature_err(&self.session.parse_sess, "tool_attributes",
- invoc.span(), GateIssue::Language,
- "tool attributes are unstable").emit();
- }
- if attr_kind == NonMacroAttrKind::Custom {
- assert!(path.segments.len() == 1);
- let name = path.segments[0].ident.name.as_str();
- if name.starts_with("rustc_") {
- if !features.rustc_attrs {
- let msg = "unless otherwise specified, attributes with the prefix \
- `rustc_` are reserved for internal compiler diagnostics";
- feature_err(&self.session.parse_sess, "rustc_attrs", invoc.span(),
- GateIssue::Language, &msg).emit();
- }
- } else if name.starts_with("derive_") {
- if !features.custom_derive {
- feature_err(&self.session.parse_sess, "custom_derive", invoc.span(),
- GateIssue::Language, EXPLAIN_DERIVE_UNDERSCORE).emit();
- }
- } else if !features.custom_attribute {
- let msg = format!("The attribute `{}` is currently unknown to the \
- compiler and may have meaning added to it in the \
- future", path);
- feature_err(&self.session.parse_sess, "custom_attribute", invoc.span(),
- GateIssue::Language, &msg).emit();
- }
- }
- return Ok(Some(Lrc::new(SyntaxExtension::NonMacroAttr {
- mark_used: attr_kind == NonMacroAttrKind::Tool,
- })));
- }
- _ => {
- self.report_non_macro_attr(path.span, def);
- return Err(Determinacy::Determined);
- }
- }
+ let (def, ext) = self.resolve_macro_to_def(path, kind, scope, derives_in_scope, force)?;
+
+ if let Def::Macro(def_id, _) = def {
+ self.macro_defs.insert(invoc.expansion_data.mark, def_id);
+ let normal_module_def_id =
+ self.macro_def_scope(invoc.expansion_data.mark).normal_ancestor_id;
+ self.definitions.add_parent_module_of_macro_def(invoc.expansion_data.mark,
+ normal_module_def_id);
+ invoc.expansion_data.mark.set_default_transparency(ext.default_transparency());
+ invoc.expansion_data.mark.set_is_builtin(def_id.krate == BUILTIN_MACROS_CRATE);
}
- let def_id = def.def_id();
-
- self.macro_defs.insert(invoc.expansion_data.mark, def_id);
- let normal_module_def_id =
- self.macro_def_scope(invoc.expansion_data.mark).normal_ancestor_id;
- self.definitions.add_parent_module_of_macro_def(invoc.expansion_data.mark,
- normal_module_def_id);
-
- self.unused_macros.remove(&def_id);
- let ext = self.get_macro(def);
- invoc.expansion_data.mark.set_default_transparency(ext.default_transparency());
- invoc.expansion_data.mark.set_is_builtin(def_id.krate == BUILTIN_MACROS_CRATE);
+
Ok(Some(ext))
}
- fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
- -> Result<Lrc<SyntaxExtension>, Determinacy> {
- self.resolve_macro_to_def(scope, path, kind, force).and_then(|def| {
- if let Def::Macro(_, MacroKind::ProcMacroStub) = def {
- self.report_proc_macro_stub(path.span);
- return Err(Determinacy::Determined);
- } else if let Def::NonMacroAttr(..) = def {
- self.report_non_macro_attr(path.span, def);
- return Err(Determinacy::Determined);
- }
- self.unused_macros.remove(&def.def_id());
- Ok(self.get_macro(def))
- })
+ fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, scope: Mark,
+ derives_in_scope: &[ast::Path], force: bool)
+ -> Result<Lrc<SyntaxExtension>, Determinacy> {
+ Ok(self.resolve_macro_to_def(path, kind, scope, derives_in_scope, force)?.1)
}
fn check_unused_macros(&self) {
}
impl<'a, 'cl> Resolver<'a, 'cl> {
- fn report_proc_macro_stub(&self, span: Span) {
- self.session.span_err(span,
- "can't use a procedural macro from the same crate that defines it");
- }
+ fn resolve_macro_to_def(&mut self, path: &ast::Path, kind: MacroKind, scope: Mark,
+ derives_in_scope: &[ast::Path], force: bool)
+ -> Result<(Def, Lrc<SyntaxExtension>), Determinacy> {
+ let def = self.resolve_macro_to_def_inner(path, kind, scope, derives_in_scope, force);
- fn report_non_macro_attr(&self, span: Span, def: Def) {
- self.session.span_err(span, &format!("expected a macro, found {}", def.kind_name()));
- }
-
- fn resolve_invoc_to_def(&mut self, invoc: &Invocation, scope: Mark, force: bool)
- -> Result<Def, Determinacy> {
- let (attr, traits) = match invoc.kind {
- InvocationKind::Attr { ref attr, ref traits, .. } => (attr, traits),
- InvocationKind::Bang { ref mac, .. } => {
- return self.resolve_macro_to_def(scope, &mac.node.path, MacroKind::Bang, force);
- }
- InvocationKind::Derive { ref path, .. } => {
- return self.resolve_macro_to_def(scope, path, MacroKind::Derive, force);
+ // Report errors and enforce feature gates for the resolved macro.
+ if def != Err(Determinacy::Undetermined) {
+ // Do not report duplicated errors on every undetermined resolution.
+ for segment in &path.segments {
+ if let Some(args) = &segment.args {
+ self.session.span_err(args.span(), "generic arguments in macro path");
+ }
}
- };
-
- let path = attr.as_ref().unwrap().path.clone();
- let def = self.resolve_macro_to_def(scope, &path, MacroKind::Attr, force);
- if let Ok(Def::NonMacroAttr(NonMacroAttrKind::Custom)) = def {} else {
- return def;
}
- // At this point we've found that the `attr` is determinately unresolved and thus can be
- // interpreted as a custom attribute. Normally custom attributes are feature gated, but
- // it may be a custom attribute whitelisted by a derive macro and they do not require
- // a feature gate.
- //
- // So here we look through all of the derive annotations in scope and try to resolve them.
- // If they themselves successfully resolve *and* one of the resolved derive macros
- // whitelists this attribute's name, then this is a registered attribute and we can convert
- // it from a "generic custom attrite" into a "known derive helper attribute".
- enum ConvertToDeriveHelper { Yes, No, DontKnow }
- let mut convert_to_derive_helper = ConvertToDeriveHelper::No;
- let attr_name = path.segments[0].ident.name;
- for path in traits {
- match self.resolve_macro(scope, path, MacroKind::Derive, force) {
- Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs, _) = *ext {
- if inert_attrs.contains(&attr_name) {
- convert_to_derive_helper = ConvertToDeriveHelper::Yes;
- break
- }
- },
- Err(Determinacy::Undetermined) =>
- convert_to_derive_helper = ConvertToDeriveHelper::DontKnow,
- Err(Determinacy::Determined) => {}
- }
- }
+ let def = def?;
- match convert_to_derive_helper {
- ConvertToDeriveHelper::Yes => Ok(Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper)),
- ConvertToDeriveHelper::No => def,
- ConvertToDeriveHelper::DontKnow => Err(Determinacy::determined(force)),
+ if path.segments.len() > 1 {
+ if kind != MacroKind::Bang {
+ if def != Def::NonMacroAttr(NonMacroAttrKind::Tool) &&
+ !self.session.features_untracked().proc_macro_path_invoc {
+ let msg = format!("non-ident {} paths are unstable", kind.descr());
+ emit_feature_err(&self.session.parse_sess, "proc_macro_path_invoc",
+ path.span, GateIssue::Language, &msg);
+ }
+ }
}
- }
- fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
- -> Result<Def, Determinacy> {
- let def = self.resolve_macro_to_def_inner(scope, path, kind, force);
- if def != Err(Determinacy::Undetermined) {
- // Do not report duplicated errors on every undetermined resolution.
- path.segments.iter().find(|segment| segment.args.is_some()).map(|segment| {
- self.session.span_err(segment.args.as_ref().unwrap().span(),
- "generic arguments in macro path");
- });
- }
- if kind != MacroKind::Bang && path.segments.len() > 1 &&
- def != Ok(Def::NonMacroAttr(NonMacroAttrKind::Tool)) {
- if !self.session.features_untracked().proc_macro_path_invoc {
- emit_feature_err(
- &self.session.parse_sess,
- "proc_macro_path_invoc",
- path.span,
- GateIssue::Language,
- "paths of length greater than one in macro invocations are \
- currently unstable",
- );
+ match def {
+ Def::Macro(def_id, macro_kind) => {
+ self.unused_macros.remove(&def_id);
+ if macro_kind == MacroKind::ProcMacroStub {
+ let msg = "can't use a procedural macro from the same crate that defines it";
+ self.session.span_err(path.span, msg);
+ return Err(Determinacy::Determined);
+ }
+ }
+ Def::NonMacroAttr(attr_kind) => {
+ if kind == MacroKind::Attr {
+ let features = self.session.features_untracked();
+ if attr_kind == NonMacroAttrKind::Tool && !features.tool_attributes {
+ feature_err(&self.session.parse_sess, "tool_attributes", path.span,
+ GateIssue::Language, "tool attributes are unstable").emit();
+ }
+ if attr_kind == NonMacroAttrKind::Custom {
+ assert!(path.segments.len() == 1);
+ let name = path.segments[0].ident.name.as_str();
+ if name.starts_with("rustc_") {
+ if !features.rustc_attrs {
+ let msg = "unless otherwise specified, attributes with the prefix \
+ `rustc_` are reserved for internal compiler diagnostics";
+ feature_err(&self.session.parse_sess, "rustc_attrs", path.span,
+ GateIssue::Language, &msg).emit();
+ }
+ } else if name.starts_with("derive_") {
+ if !features.custom_derive {
+ feature_err(&self.session.parse_sess, "custom_derive", path.span,
+ GateIssue::Language, EXPLAIN_DERIVE_UNDERSCORE).emit();
+ }
+ } else if !features.custom_attribute {
+ let msg = format!("The attribute `{}` is currently unknown to the \
+ compiler and may have meaning added to it in the \
+ future", path);
+ feature_err(&self.session.parse_sess, "custom_attribute", path.span,
+ GateIssue::Language, &msg).emit();
+ }
+ }
+ } else {
+ // Not only attributes, but anything in macro namespace can result in
+ // `Def::NonMacroAttr` definition (e.g. `inline!()`), so we must report
+ // an error for those cases.
+ let msg = format!("expected a macro, found {}", def.kind_name());
+ self.session.span_err(path.span, &msg);
+ return Err(Determinacy::Determined);
+ }
}
+ _ => panic!("expected `Def::Macro` or `Def::NonMacroAttr`"),
}
- def
+
+ Ok((def, self.get_macro(def)))
}
- pub fn resolve_macro_to_def_inner(&mut self, scope: Mark, path: &ast::Path,
- kind: MacroKind, force: bool)
- -> Result<Def, Determinacy> {
+ pub fn resolve_macro_to_def_inner(&mut self, path: &ast::Path, kind: MacroKind, scope: Mark,
+ derives_in_scope: &[ast::Path], force: bool)
+ -> Result<Def, Determinacy> {
let ast::Path { ref segments, span } = *path;
let mut path: Vec<_> = segments.iter().map(|seg| seg.ident).collect();
let invocation = self.invocations[&scope];
}
let legacy_resolution = self.resolve_legacy_scope(&invocation.legacy_scope, path[0], false);
- let result = if let Some(MacroBinding::Legacy(binding)) = legacy_resolution {
- Ok(Def::Macro(binding.def_id, MacroKind::Bang))
+ let result = if let Some((legacy_binding, _)) = legacy_resolution {
+ Ok(legacy_binding.def())
} else {
match self.resolve_lexical_macro_path_segment(path[0], MacroNS, false, force,
kind == MacroKind::Attr, span) {
- Ok(binding) => Ok(binding.binding().def_ignoring_ambiguity()),
+ Ok((binding, _)) => Ok(binding.def_ignoring_ambiguity()),
Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
Err(Determinacy::Determined) => {
self.found_unresolved_macro = true;
self.current_module.nearest_item_scope().legacy_macro_resolutions.borrow_mut()
.push((scope, path[0], kind, result.ok()));
- result
+ if let Ok(Def::NonMacroAttr(NonMacroAttrKind::Custom)) = result {} else {
+ return result;
+ }
+
+ // At this point we've found that the `attr` is determinately unresolved and thus can be
+ // interpreted as a custom attribute. Normally custom attributes are feature gated, but
+ // it may be a custom attribute whitelisted by a derive macro and they do not require
+ // a feature gate.
+ //
+ // So here we look through all of the derive annotations in scope and try to resolve them.
+ // If they themselves successfully resolve *and* one of the resolved derive macros
+ // whitelists this attribute's name, then this is a registered attribute and we can convert
+ // it from a "generic custom attrite" into a "known derive helper attribute".
+ assert!(kind == MacroKind::Attr);
+ enum ConvertToDeriveHelper { Yes, No, DontKnow }
+ let mut convert_to_derive_helper = ConvertToDeriveHelper::No;
+ for derive in derives_in_scope {
+ match self.resolve_macro_path(derive, MacroKind::Derive, scope, &[], force) {
+ Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs, _) = *ext {
+ if inert_attrs.contains(&path[0].name) {
+ convert_to_derive_helper = ConvertToDeriveHelper::Yes;
+ break
+ }
+ },
+ Err(Determinacy::Undetermined) =>
+ convert_to_derive_helper = ConvertToDeriveHelper::DontKnow,
+ Err(Determinacy::Determined) => {}
+ }
+ }
+
+ match convert_to_derive_helper {
+ ConvertToDeriveHelper::Yes => Ok(Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper)),
+ ConvertToDeriveHelper::No => result,
+ ConvertToDeriveHelper::DontKnow => Err(Determinacy::determined(force)),
+ }
}
// Resolve the initial segment of a non-global macro path
// (e.g. `foo` in `foo::bar!(); or `foo!();`).
// This is a variation of `fn resolve_ident_in_lexical_scope` that can be run during
// expansion and import resolution (perhaps they can be merged in the future).
- pub fn resolve_lexical_macro_path_segment(&mut self,
- mut ident: Ident,
- ns: Namespace,
- record_used: bool,
- force: bool,
- is_attr: bool,
- path_span: Span)
- -> Result<MacroBinding<'a>, Determinacy> {
+ crate fn resolve_lexical_macro_path_segment(
+ &mut self,
+ mut ident: Ident,
+ ns: Namespace,
+ record_used: bool,
+ force: bool,
+ is_attr: bool,
+ path_span: Span
+ ) -> Result<(&'a NameBinding<'a>, FromPrelude), Determinacy> {
// General principles:
// 1. Not controlled (user-defined) names should have higher priority than controlled names
// built into the language or standard library. This way we can add new names into the
// m::mac!();
// }
// This includes names from globs and from macro expansions.
- let mut potentially_ambiguous_result: Option<MacroBinding> = None;
+ let mut potentially_ambiguous_result: Option<(&NameBinding, FromPrelude)> = None;
enum WhereToResolve<'a> {
Module(Module<'a>),
path_span,
);
self.current_module = orig_current_module;
- binding.map(MacroBinding::Modern)
+ binding.map(|binding| (binding, FromPrelude(false)))
}
WhereToResolve::MacroPrelude => {
match self.macro_prelude.get(&ident.name).cloned() {
- Some(binding) => Ok(MacroBinding::Global(binding)),
+ Some(binding) => Ok((binding, FromPrelude(true))),
None => Err(Determinacy::Determined),
}
}
let binding = (Def::NonMacroAttr(NonMacroAttrKind::Builtin),
ty::Visibility::Public, ident.span, Mark::root())
.to_name_binding(self.arenas);
- Ok(MacroBinding::Global(binding))
+ Ok((binding, FromPrelude(true)))
} else {
Err(Determinacy::Determined)
}
let binding = (crate_root, ty::Visibility::Public,
ident.span, Mark::root()).to_name_binding(self.arenas);
- Ok(MacroBinding::Global(binding))
+ Ok((binding, FromPrelude(true)))
} else {
Err(Determinacy::Determined)
}
if use_prelude && is_known_tool(ident.name) {
let binding = (Def::ToolMod, ty::Visibility::Public,
ident.span, Mark::root()).to_name_binding(self.arenas);
- Ok(MacroBinding::Global(binding))
+ Ok((binding, FromPrelude(true)))
} else {
Err(Determinacy::Determined)
}
false,
path_span,
) {
- result = Ok(MacroBinding::Global(binding));
+ result = Ok((binding, FromPrelude(true)));
}
}
}
self.primitive_type_table.primitive_types.get(&ident.name).cloned() {
let binding = (Def::PrimTy(prim_ty), ty::Visibility::Public,
ident.span, Mark::root()).to_name_binding(self.arenas);
- Ok(MacroBinding::Global(binding))
+ Ok((binding, FromPrelude(true)))
} else {
Err(Determinacy::Determined)
}
return Ok(result);
}
- let binding = result.binding();
-
// Found a solution that is ambiguous with a previously found solution.
// Push an ambiguity error for later reporting and
// return something for better recovery.
if let Some(previous_result) = potentially_ambiguous_result {
- if binding.def() != previous_result.binding().def() {
+ if result.0.def() != previous_result.0.def() {
self.ambiguity_errors.push(AmbiguityError {
span: path_span,
name: ident.name,
- b1: previous_result.binding(),
- b2: binding,
+ b1: previous_result.0,
+ b2: result.0,
lexical: true,
});
return Ok(previous_result);
// Found a solution that's not an ambiguity yet, but is "suspicious" and
// can participate in ambiguities later on.
// Remember it and go search for other solutions in outer scopes.
- if binding.is_glob_import() || binding.expansion != Mark::root() {
+ if result.0.is_glob_import() || result.0.expansion != Mark::root() {
potentially_ambiguous_result = Some(result);
continue_search!();
let binding = (Def::NonMacroAttr(NonMacroAttrKind::Custom),
ty::Visibility::Public, ident.span, Mark::root())
.to_name_binding(self.arenas);
- Ok(MacroBinding::Global(binding))
+ Ok((binding, FromPrelude(true)))
} else {
Err(determinacy)
}
}
- pub fn resolve_legacy_scope(&mut self,
- mut scope: &'a Cell<LegacyScope<'a>>,
- ident: Ident,
- record_used: bool)
- -> Option<MacroBinding<'a>> {
+ crate fn resolve_legacy_scope(&mut self,
+ mut scope: &'a Cell<LegacyScope<'a>>,
+ ident: Ident,
+ record_used: bool)
+ -> Option<(&'a LegacyBinding<'a>, FromExpansion)> {
let ident = ident.modern();
let mut relative_depth: u32 = 0;
- let mut binding = None;
loop {
match scope.get() {
LegacyScope::Empty => break,
if record_used && relative_depth > 0 {
self.disallowed_shadowing.push(potential_binding);
}
- binding = Some(potential_binding);
- break
+ return Some((potential_binding, FromExpansion(relative_depth > 0)));
}
scope = &potential_binding.parent;
}
};
}
- let binding = if let Some(binding) = binding {
- MacroBinding::Legacy(binding)
- } else if let Some(binding) = self.macro_prelude.get(&ident.name).cloned() {
- MacroBinding::Global(binding)
- } else {
- return None;
- };
-
- Some(binding)
+ None
}
pub fn finalize_current_module_macro_resolutions(&mut self) {
let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, true, true,
kind == MacroKind::Attr, span);
- let check_consistency = |this: &Self, binding: MacroBinding| {
+ let check_consistency = |this: &Self, new_def: Def| {
if let Some(def) = def {
if this.ambiguity_errors.is_empty() && this.disallowed_shadowing.is_empty() &&
- binding.def_ignoring_ambiguity() != def {
+ new_def != def && new_def != Def::Err {
// Make sure compilation does not succeed if preferred macro resolution
// has changed after the macro had been expanded. In theory all such
// situations should be reported as ambiguity errors, so this is span-bug.
};
match (legacy_resolution, resolution) {
- (Some(MacroBinding::Legacy(legacy_binding)), Ok(MacroBinding::Modern(binding))) => {
- if legacy_binding.def_id != binding.def_ignoring_ambiguity().def_id() {
- let msg1 = format!("`{}` could refer to the macro defined here", ident);
- let msg2 =
- format!("`{}` could also refer to the macro imported here", ident);
- self.session.struct_span_err(span, &format!("`{}` is ambiguous", ident))
- .span_note(legacy_binding.span, &msg1)
- .span_note(binding.span, &msg2)
- .emit();
- }
- },
(None, Err(_)) => {
assert!(def.is_none());
let bang = if kind == MacroKind::Bang { "!" } else { "" };
self.suggest_macro_name(&ident.as_str(), kind, &mut err, span);
err.emit();
},
- (Some(MacroBinding::Modern(_)), _) | (_, Ok(MacroBinding::Legacy(_))) => {
- span_bug!(span, "impossible macro resolution result");
- }
+ (Some((legacy_binding, FromExpansion(from_expansion))),
+ Ok((binding, FromPrelude(false)))) |
+ (Some((legacy_binding, FromExpansion(from_expansion @ true))),
+ Ok((binding, FromPrelude(true)))) => {
+ if legacy_binding.def() != binding.def_ignoring_ambiguity() {
+ self.report_ambiguity_error(
+ ident.name, span, true,
+ legacy_binding.def(), false, false,
+ from_expansion, legacy_binding.span,
+ binding.def(), binding.is_import(), binding.is_glob_import(),
+ binding.expansion != Mark::root(), binding.span,
+ );
+ }
+ },
+ // OK, non-macro-expanded legacy wins over macro prelude even if defs are different
+ (Some((legacy_binding, FromExpansion(false))), Ok((_, FromPrelude(true)))) |
// OK, unambiguous resolution
- (Some(binding), Err(_)) | (None, Ok(binding)) |
- // OK, legacy wins over global even if their definitions are different
- (Some(binding @ MacroBinding::Legacy(_)), Ok(MacroBinding::Global(_))) |
- // OK, modern wins over global even if their definitions are different
- (Some(MacroBinding::Global(_)), Ok(binding @ MacroBinding::Modern(_))) => {
- check_consistency(self, binding);
+ (Some((legacy_binding, _)), Err(_)) => {
+ check_consistency(self, legacy_binding.def());
}
- (Some(MacroBinding::Global(binding1)), Ok(MacroBinding::Global(binding2))) => {
- if binding1.def() != binding2.def() {
- span_bug!(span, "mismatch between same global macro resolutions");
+ // OK, unambiguous resolution
+ (None, Ok((binding, FromPrelude(from_prelude)))) => {
+ check_consistency(self, binding.def_ignoring_ambiguity());
+ if from_prelude {
+ self.record_use(ident, MacroNS, binding, span);
+ self.err_if_macro_use_proc_macro(ident.name, span, binding);
}
- check_consistency(self, MacroBinding::Global(binding1));
-
- self.record_use(ident, MacroNS, binding1, span);
- self.err_if_macro_use_proc_macro(ident.name, span, binding1);
- },
+ }
};
}
}
if let Some(suggestion) = suggestion {
if suggestion != name {
if let MacroKind::Bang = kind {
- err.span_suggestion(span, "you could try the macro", suggestion.to_string());
+ err.span_suggestion_with_applicability(
+ span,
+ "you could try the macro",
+ suggestion.to_string(),
+ Applicability::MaybeIncorrect
+ );
} else {
- err.span_suggestion(span, "try", suggestion.to_string());
+ err.span_suggestion_with_applicability(
+ span,
+ "try",
+ suggestion.to_string(),
+ Applicability::MaybeIncorrect
+ );
}
} else {
err.help("have you added the `#[macro_use]` on the module/import?");
/// Error if `ext` is a Macros 1.1 procedural macro being imported by `#[macro_use]`
fn err_if_macro_use_proc_macro(&mut self, name: Name, use_span: Span,
binding: &NameBinding<'a>) {
- let krate = binding.def().def_id().krate;
+ let krate = match binding.def() {
+ Def::NonMacroAttr(..) | Def::Err => return,
+ Def::Macro(def_id, _) => def_id.krate,
+ _ => unreachable!(),
+ };
// Plugin-based syntax extensions are exempt from this check
if krate == BUILTIN_MACROS_CRATE { return; }
if let Some(span) = span {
let found_use = if found_use { "" } else { "\n" };
self.session.struct_span_err(err.use_span, err.warn_msg)
- .span_suggestion(
+ .span_suggestion_with_applicability(
span,
"instead, import the procedural macro like any other item",
format!("use {}::{};{}", err.crate_name, err.name, found_use),
+ Applicability::MachineApplicable
).emit();
} else {
self.session.struct_span_err(err.use_span, err.warn_msg)
use rustc::ty::fold::TypeFoldable;
use rustc::ty::query::Providers;
use rustc::ty::util::{Representability, IntTypeExt, Discr};
- use errors::{DiagnosticBuilder, DiagnosticId};
+ use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
use require_c_abi_if_variadic;
use session::{CompileIncomplete, config, Session};
use TypeAndSubsts;
use lint;
use util::common::{ErrorReported, indenter};
-use util::nodemap::{DefIdMap, DefIdSet, FxHashMap, NodeMap};
+use util::nodemap::{DefIdMap, DefIdSet, FxHashMap, FxHashSet, NodeMap};
use std::cell::{Cell, RefCell, Ref, RefMut};
use rustc_data_structures::sync::Lrc;
}
}
+#[derive(Debug)]
+struct PathSeg(DefId, usize);
+
pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
body_id: ast::NodeId,
// backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
fcx.check_casts();
- // Closure and generater analysis may run after fallback
+ // Closure and generator analysis may run after fallback
// because they don't constrain other type variables.
fcx.closure_analyze(body);
assert!(fcx.deferred_call_resolutions.borrow().is_empty());
};
let param_env = ty::ParamEnv::reveal_all();
if let Ok(static_) = tcx.const_eval(param_env.and(cid)) {
- let alloc = tcx.const_value_to_allocation(static_);
+ let alloc = tcx.const_to_allocation(static_);
if alloc.relocations.len() != 0 {
let msg = "statics with a custom `#[link_section]` must be a \
simple list of bytes on the wasm target with no \
// unconstrained floats with f64.
// Fallback becomes very dubious if we have encountered type-checking errors.
// In that case, fallback to TyError.
- // The return value indicates whether fallback has occured.
+ // The return value indicates whether fallback has occurred.
fn fallback_if_possible(&self, ty: Ty<'tcx>) -> bool {
use rustc::ty::error::UnconstrainedNumeric::Neither;
use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
let sugg_span = tcx.sess.source_map().end_point(expr_sp);
// remove closing `)` from the span
let sugg_span = sugg_span.shrink_to_lo();
- err.span_suggestion(
+ err.span_suggestion_with_applicability(
sugg_span,
"expected the unit value `()`; create it with empty parentheses",
- String::from("()"));
+ String::from("()"),
+ Applicability::MachineApplicable);
} else {
err.span_label(sp, format!("expected {}{} parameter{}",
if variadic {"at least "} else {""},
self.tcx.sess.source_map().span_to_snippet(lhs.span),
self.tcx.sess.source_map().span_to_snippet(rhs.span))
{
- err.span_suggestion(expr.span, msg, format!("{} == {}", left, right));
+ err.span_suggestion_with_applicability(
+ expr.span,
+ msg,
+ format!("{} == {}", left, right),
+ Applicability::MaybeIncorrect);
} else {
err.help(msg);
}
ast::LitIntType::Unsuffixed) = lit.node {
let snip = tcx.sess.source_map().span_to_snippet(base.span);
if let Ok(snip) = snip {
- err.span_suggestion(expr.span,
- "to access tuple elements, use",
- format!("{}.{}", snip, i));
+ err.span_suggestion_with_applicability(
+ expr.span,
+ "to access tuple elements, use",
+ format!("{}.{}", snip, i),
+ Applicability::MachineApplicable);
needs_note = false;
}
}
{
match *qpath {
hir::QPath::Resolved(ref maybe_qself, ref path) => {
- let opt_self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself));
- let ty = AstConv::def_to_ty(self, opt_self_ty, path, true);
+ let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself));
+ let ty = AstConv::def_to_ty(self, self_ty, path, true);
(path.def, ty)
}
hir::QPath::TypeRelative(ref qself, ref segment) => {
hir::ExprKind::Match(..) |
hir::ExprKind::Block(..) => {
let sp = self.tcx.sess.source_map().next_point(cause_span);
- err.span_suggestion(sp,
- "try adding a semicolon",
- ";".to_string());
+ err.span_suggestion_with_applicability(
+ sp,
+ "try adding a semicolon",
+ ";".to_string(),
+ Applicability::MachineApplicable);
}
_ => (),
}
// haven't set a return type at all (and aren't `fn main()` or an impl).
match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_nil()) {
(&hir::FunctionRetTy::DefaultReturn(span), true, true, true) => {
- err.span_suggestion(span,
- "try adding a return type",
- format!("-> {} ",
- self.resolve_type_vars_with_obligations(found)));
+ err.span_suggestion_with_applicability(
+ span,
+ "try adding a return type",
+ format!("-> {} ", self.resolve_type_vars_with_obligations(found)),
+ Applicability::MachineApplicable);
}
(&hir::FunctionRetTy::DefaultReturn(span), false, true, true) => {
err.span_label(span, "possibly return type missing here?");
}
let original_span = original_sp(last_stmt.span, blk.span);
let span_semi = original_span.with_lo(original_span.hi() - BytePos(1));
- err.span_suggestion(span_semi, "consider removing this semicolon", "".to_string());
+ err.span_suggestion_with_applicability(
+ span_semi,
+ "consider removing this semicolon",
+ "".to_string(),
+ Applicability::MachineApplicable);
}
- // Instantiates the given path, which must refer to an item with the given
- // number of type parameters and type.
- pub fn instantiate_value_path(&self,
- segments: &[hir::PathSegment],
- opt_self_ty: Option<Ty<'tcx>>,
- def: Def,
- span: Span,
- node_id: ast::NodeId)
- -> Ty<'tcx> {
- debug!("instantiate_value_path(path={:?}, def={:?}, node_id={})",
- segments,
- def,
- node_id);
-
+ fn def_ids_for_path_segments(&self,
+ segments: &[hir::PathSegment],
+ def: Def)
+ -> Vec<PathSeg> {
// We need to extract the type parameters supplied by the user in
// the path `path`. Due to the current setup, this is a bit of a
// tricky-process; the problem is that resolve only tells us the
// The first step then is to categorize the segments appropriately.
assert!(!segments.is_empty());
+ let last = segments.len() - 1;
+
+ let mut path_segs = vec![];
- let mut ufcs_associated = None;
- let mut type_segment = None;
- let mut fn_segment = None;
match def {
// Case 1. Reference to a struct/variant constructor.
Def::StructCtor(def_id, ..) |
Def::VariantCtor(def_id, ..) => {
// Everything but the final segment should have no
// parameters at all.
- let mut generics = self.tcx.generics_of(def_id);
- if let Some(def_id) = generics.parent {
- // Variant and struct constructors use the
- // generics of their parent type definition.
- generics = self.tcx.generics_of(def_id);
- }
- type_segment = Some((segments.last().unwrap(), generics));
+ let generics = self.tcx.generics_of(def_id);
+ // Variant and struct constructors use the
+ // generics of their parent type definition.
+ let generics_def_id = generics.parent.unwrap_or(def_id);
+ path_segs.push(PathSeg(generics_def_id, last));
}
// Case 2. Reference to a top-level value.
Def::Fn(def_id) |
Def::Const(def_id) |
Def::Static(def_id, _) => {
- fn_segment = Some((segments.last().unwrap(), self.tcx.generics_of(def_id)));
+ path_segs.push(PathSeg(def_id, last));
}
// Case 3. Reference to a method or associated const.
+ Def::Method(def_id) |
+ Def::AssociatedConst(def_id) => {
+ if segments.len() >= 2 {
+ let generics = self.tcx.generics_of(def_id);
+ path_segs.push(PathSeg(generics.parent.unwrap(), last - 1));
+ }
+ path_segs.push(PathSeg(def_id, last));
+ }
+
+ // Case 4. Local variable, no generics.
+ Def::Local(..) | Def::Upvar(..) => {}
+
+ _ => bug!("unexpected definition: {:?}", def),
+ }
+
+ debug!("path_segs = {:?}", path_segs);
+
+ path_segs
+ }
+
+ // Instantiates the given path, which must refer to an item with the given
+ // number of type parameters and type.
+ pub fn instantiate_value_path(&self,
+ segments: &[hir::PathSegment],
+ self_ty: Option<Ty<'tcx>>,
+ def: Def,
+ span: Span,
+ node_id: ast::NodeId)
+ -> Ty<'tcx> {
+ debug!("instantiate_value_path(path={:?}, def={:?}, node_id={})",
+ segments,
+ def,
+ node_id);
+
+ let path_segs = self.def_ids_for_path_segments(segments, def);
+
+ let mut ufcs_associated = None;
+ match def {
Def::Method(def_id) |
Def::AssociatedConst(def_id) => {
let container = self.tcx.associated_item(def_id).container;
}
ty::ImplContainer(_) => {}
}
-
- let generics = self.tcx.generics_of(def_id);
- if segments.len() >= 2 {
- let parent_generics = self.tcx.generics_of(generics.parent.unwrap());
- type_segment = Some((&segments[segments.len() - 2], parent_generics));
- } else {
+ if segments.len() == 1 {
// `<T>::assoc` will end up here, and so can `T::assoc`.
- let self_ty = opt_self_ty.expect("UFCS sugared assoc missing Self");
+ let self_ty = self_ty.expect("UFCS sugared assoc missing Self");
ufcs_associated = Some((container, self_ty));
}
- fn_segment = Some((segments.last().unwrap(), generics));
}
-
- // Case 4. Local variable, no generics.
- Def::Local(..) | Def::Upvar(..) => {}
-
- _ => bug!("unexpected definition: {:?}", def),
+ _ => {}
}
- debug!("type_segment={:?} fn_segment={:?}", type_segment, fn_segment);
-
// Now that we have categorized what space the parameters for each
// segment belong to, let's sort out the parameters that the user
// provided (if any) into their appropriate spaces. We'll also report
// errors if type parameters are provided in an inappropriate place.
- let poly_segments = type_segment.is_some() as usize +
- fn_segment.is_some() as usize;
- AstConv::prohibit_generics(self, &segments[..segments.len() - poly_segments]);
+
+ let mut generic_segs = FxHashSet::default();
+ for PathSeg(_, index) in &path_segs {
+ generic_segs.insert(index);
+ }
+ AstConv::prohibit_generics(self, segments.iter().enumerate().filter_map(|(index, seg)| {
+ if !generic_segs.contains(&index) {
+ Some(seg)
+ } else {
+ None
+ }
+ }));
match def {
Def::Local(nid) | Def::Upvar(nid, ..) => {
// variables. If the user provided some types, we may still need
// to add defaults. If the user provided *too many* types, that's
// a problem.
- let supress_mismatch = self.check_impl_trait(span, fn_segment);
- self.check_generic_arg_count(span, &mut type_segment, false, supress_mismatch);
- self.check_generic_arg_count(span, &mut fn_segment, false, supress_mismatch);
- let (fn_start, has_self) = match (type_segment, fn_segment) {
- (_, Some((_, generics))) => {
- (generics.parent_count, generics.has_self)
- }
- (Some((_, generics)), None) => {
- (generics.params.len(), generics.has_self)
- }
- (None, None) => (0, false)
- };
- // FIXME(varkor): Separating out the parameters is messy.
- let mut lifetimes_type_seg = vec![];
- let mut types_type_seg = vec![];
- let mut infer_types_type_seg = true;
- if let Some((seg, _)) = type_segment {
- if let Some(ref data) = seg.args {
- for arg in &data.args {
- match arg {
- GenericArg::Lifetime(lt) => lifetimes_type_seg.push(lt),
- GenericArg::Type(ty) => types_type_seg.push(ty),
- }
- }
+ let mut infer_args_for_err = FxHashSet::default();
+ for &PathSeg(def_id, index) in &path_segs {
+ let seg = &segments[index];
+ let generics = self.tcx.generics_of(def_id);
+ // Argument-position `impl Trait` is treated as a normal generic
+ // parameter internally, but we don't allow users to specify the
+ // parameter's value explicitly, so we have to do some error-
+ // checking here.
+ let suppress_errors = AstConv::check_generic_arg_count_for_call(
+ self.tcx,
+ span,
+ &generics,
+ &seg,
+ false, // `is_method_call`
+ );
+ if suppress_errors {
+ infer_args_for_err.insert(index);
+ self.set_tainted_by_errors(); // See issue #53251.
}
- infer_types_type_seg = seg.infer_types;
}
- let mut lifetimes_fn_seg = vec![];
- let mut types_fn_seg = vec![];
- let mut infer_types_fn_seg = true;
- if let Some((seg, _)) = fn_segment {
- if let Some(ref data) = seg.args {
- for arg in &data.args {
- match arg {
- GenericArg::Lifetime(lt) => lifetimes_fn_seg.push(lt),
- GenericArg::Type(ty) => types_fn_seg.push(ty),
- }
- }
- }
- infer_types_fn_seg = seg.infer_types;
- }
+ let has_self = path_segs.last().map(|PathSeg(def_id, _)| {
+ self.tcx.generics_of(*def_id).has_self
+ }).unwrap_or(false);
- let substs = Substs::for_item(self.tcx, def.def_id(), |param, substs| {
- let mut i = param.index as usize;
+ let def_id = def.def_id();
- let (segment, lifetimes, types, infer_types) = if i < fn_start {
- if let GenericParamDefKind::Type { .. } = param.kind {
- // Handle Self first, so we can adjust the index to match the AST.
- if has_self && i == 0 {
- return opt_self_ty.map(|ty| ty.into()).unwrap_or_else(|| {
- self.var_for_def(span, param)
- });
+ let substs = AstConv::create_substs_for_generic_args(
+ self.tcx,
+ def_id,
+ &[][..],
+ has_self,
+ self_ty,
+ // Provide the generic args, and whether types should be inferred.
+ |def_id| {
+ if let Some(&PathSeg(_, index)) = path_segs.iter().find(|&PathSeg(did, _)| {
+ *did == def_id
+ }) {
+ // If we've encountered an `impl Trait`-related error, we're just
+ // going to infer the arguments for better error messages.
+ if !infer_args_for_err.contains(&index) {
+ // Check whether the user has provided generic arguments.
+ if let Some(ref data) = segments[index].args {
+ return (Some(data), segments[index].infer_types);
+ }
}
+ return (None, segments[index].infer_types);
}
- i -= has_self as usize;
- (type_segment, &lifetimes_type_seg, &types_type_seg, infer_types_type_seg)
- } else {
- i -= fn_start;
- (fn_segment, &lifetimes_fn_seg, &types_fn_seg, infer_types_fn_seg)
- };
- match param.kind {
- GenericParamDefKind::Lifetime => {
- if let Some(lifetime) = lifetimes.get(i) {
- AstConv::ast_region_to_region(self, lifetime, Some(param)).into()
- } else {
- self.re_infer(span, Some(param)).unwrap().into()
+ (None, true)
+ },
+ // Provide substitutions for parameters for which (valid) arguments have been provided.
+ |param, arg| {
+ match (¶m.kind, arg) {
+ (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
+ AstConv::ast_region_to_region(self, lt, Some(param)).into()
+ }
+ (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
+ self.to_ty(ty).into()
}
+ _ => unreachable!(),
}
- GenericParamDefKind::Type { .. } => {
- // Skip over the lifetimes in the same segment.
- if let Some((_, generics)) = segment {
- i -= generics.own_counts().lifetimes;
+ },
+ // Provide substitutions for parameters for which arguments are inferred.
+ |substs, param, infer_types| {
+ match param.kind {
+ GenericParamDefKind::Lifetime => {
+ self.re_infer(span, Some(param)).unwrap().into()
}
-
- let has_default = match param.kind {
- GenericParamDefKind::Type { has_default, .. } => has_default,
- _ => unreachable!()
- };
-
- if let Some(ast_ty) = types.get(i) {
- // A provided type parameter.
- self.to_ty(ast_ty).into()
- } else if !infer_types && has_default {
- // No type parameter provided, but a default exists.
- let default = self.tcx.type_of(param.def_id);
- self.normalize_ty(
- span,
- default.subst_spanned(self.tcx, substs, Some(span))
- ).into()
- } else {
- // No type parameters were provided, we can infer all.
- // This can also be reached in some error cases:
- // We prefer to use inference variables instead of
- // TyError to let type inference recover somewhat.
- self.var_for_def(span, param)
+ GenericParamDefKind::Type { has_default, .. } => {
+ if !infer_types && has_default {
+ // If we have a default, then we it doesn't matter that we're not
+ // inferring the type arguments: we provide the default where any
+ // is missing.
+ let default = self.tcx.type_of(param.def_id);
+ self.normalize_ty(
+ span,
+ default.subst_spanned(self.tcx, substs.unwrap(), Some(span))
+ ).into()
+ } else {
+ // If no type arguments were provided, we have to infer them.
+ // This case also occurs as a result of some malformed input, e.g.
+ // a lifetime argument being given instead of a type paramter.
+ // Using inference instead of `TyError` gives better error messages.
+ self.var_for_def(span, param)
+ }
}
}
- }
- });
+ },
+ );
// The things we are substituting into the type should not contain
// escaping late-bound regions, and nor should the base type scheme.
- let ty = self.tcx.type_of(def.def_id());
+ let ty = self.tcx.type_of(def_id);
assert!(!substs.has_escaping_regions());
assert!(!ty.has_escaping_regions());
// Add all the obligations that are required, substituting and
// normalized appropriately.
- let bounds = self.instantiate_bounds(span, def.def_id(), &substs);
+ let bounds = self.instantiate_bounds(span, def_id, &substs);
self.add_obligations_for_parameters(
- traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def.def_id())),
+ traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def_id)),
&bounds);
// Substitute the values for the type parameters into the type of
}
}
- self.check_rustc_args_require_const(def.def_id(), node_id, span);
+ self.check_rustc_args_require_const(def_id, node_id, span);
debug!("instantiate_value_path: type of {:?} is {:?}",
node_id,
directly, not through a function pointer");
}
- /// Report errors if the provided parameters are too few or too many.
- fn check_generic_arg_count(&self,
- span: Span,
- segment: &mut Option<(&hir::PathSegment, &ty::Generics)>,
- is_method_call: bool,
- supress_mismatch_error: bool) {
- let (lifetimes, types, infer_types, bindings) = segment.map_or(
- (vec![], vec![], true, &[][..]),
- |(s, _)| {
- s.args.as_ref().map_or(
- (vec![], vec![], s.infer_types, &[][..]),
- |data| {
- let (mut lifetimes, mut types) = (vec![], vec![]);
- data.args.iter().for_each(|arg| match arg {
- GenericArg::Lifetime(lt) => lifetimes.push(lt),
- GenericArg::Type(ty) => types.push(ty),
- });
- (lifetimes, types, s.infer_types, &data.bindings[..])
- }
- )
- });
-
- // Check provided parameters.
- let ((ty_required, ty_accepted), lt_accepted) =
- segment.map_or(((0, 0), 0), |(_, generics)| {
- struct ParamRange {
- required: usize,
- accepted: usize
- };
-
- let mut lt_accepted = 0;
- let mut ty_params = ParamRange { required: 0, accepted: 0 };
- for param in &generics.params {
- match param.kind {
- GenericParamDefKind::Lifetime => lt_accepted += 1,
- GenericParamDefKind::Type { has_default, .. } => {
- ty_params.accepted += 1;
- if !has_default {
- ty_params.required += 1;
- }
- }
- };
- }
- if generics.parent.is_none() && generics.has_self {
- ty_params.required -= 1;
- ty_params.accepted -= 1;
- }
-
- ((ty_params.required, ty_params.accepted), lt_accepted)
- });
-
- let count_type_params = |n| {
- format!("{} type parameter{}", n, if n == 1 { "" } else { "s" })
- };
- let expected_text = count_type_params(ty_accepted);
- let actual_text = count_type_params(types.len());
- if let Some((mut err, span)) = if types.len() > ty_accepted {
- // To prevent derived errors to accumulate due to extra
- // type parameters, we force instantiate_value_path to
- // use inference variables instead of the provided types.
- *segment = None;
- let span = types[ty_accepted].span;
- Some((struct_span_err!(self.tcx.sess, span, E0087,
- "too many type parameters provided: \
- expected at most {}, found {}",
- expected_text, actual_text), span))
- } else if types.len() < ty_required && !infer_types && !supress_mismatch_error {
- Some((struct_span_err!(self.tcx.sess, span, E0089,
- "too few type parameters provided: \
- expected {}, found {}",
- expected_text, actual_text), span))
- } else {
- None
- } {
- self.set_tainted_by_errors(); // #53251
- err.span_label(span, format!("expected {}", expected_text)).emit();
- }
-
- if !bindings.is_empty() {
- AstConv::prohibit_projection(self, bindings[0].span);
- }
-
- let infer_lifetimes = lifetimes.len() == 0;
- // Prohibit explicit lifetime arguments if late bound lifetime parameters are present.
- let has_late_bound_lifetime_defs =
- segment.map_or(None, |(_, generics)| generics.has_late_bound_regions);
- if let (Some(span_late), false) = (has_late_bound_lifetime_defs, lifetimes.is_empty()) {
- // Report this as a lint only if no error was reported previously.
- let primary_msg = "cannot specify lifetime arguments explicitly \
- if late bound lifetime parameters are present";
- let note_msg = "the late bound lifetime parameter is introduced here";
- if !is_method_call && (lifetimes.len() > lt_accepted ||
- lifetimes.len() < lt_accepted && !infer_lifetimes) {
- let mut err = self.tcx.sess.struct_span_err(lifetimes[0].span, primary_msg);
- err.span_note(span_late, note_msg);
- err.emit();
- *segment = None;
- } else {
- let mut multispan = MultiSpan::from_span(lifetimes[0].span);
- multispan.push_span_label(span_late, note_msg.to_string());
- self.tcx.lint_node(lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS,
- lifetimes[0].id, multispan, primary_msg);
- }
- return;
- }
-
- let count_lifetime_params = |n| {
- format!("{} lifetime parameter{}", n, if n == 1 { "" } else { "s" })
- };
- let expected_text = count_lifetime_params(lt_accepted);
- let actual_text = count_lifetime_params(lifetimes.len());
- if let Some((mut err, span)) = if lifetimes.len() > lt_accepted {
- let span = lifetimes[lt_accepted].span;
- Some((struct_span_err!(self.tcx.sess, span, E0088,
- "too many lifetime parameters provided: \
- expected at most {}, found {}",
- expected_text, actual_text), span))
- } else if lifetimes.len() < lt_accepted && !infer_lifetimes {
- Some((struct_span_err!(self.tcx.sess, span, E0090,
- "too few lifetime parameters provided: \
- expected {}, found {}",
- expected_text, actual_text), span))
- } else {
- None
- } {
- err.span_label(span, format!("expected {}", expected_text)).emit();
- }
- }
-
- /// Report error if there is an explicit type parameter when using `impl Trait`.
- fn check_impl_trait(&self,
- span: Span,
- segment: Option<(&hir::PathSegment, &ty::Generics)>)
- -> bool {
- let segment = segment.map(|(path_segment, generics)| {
- let explicit = !path_segment.infer_types;
- let impl_trait = generics.params.iter().any(|param| match param.kind {
- ty::GenericParamDefKind::Type {
- synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), ..
- } => true,
- _ => false,
- });
-
- if explicit && impl_trait {
- let mut err = struct_span_err! {
- self.tcx.sess,
- span,
- E0632,
- "cannot provide explicit type parameters when `impl Trait` is \
- used in argument position."
- };
-
- err.emit();
- }
-
- impl_trait
- });
-
- segment.unwrap_or(false)
- }
-
// Resolves `typ` by a single level if `typ` is a type variable.
// If no resolution is possible, then an error is reported.
// Numeric inference variables may be left unresolved.