Auto merge of #65196 - Centril:rollup-q06lcxm, r=Centril
Rollup of 8 pull requests Successful merges: - #64726 (rewrite documentation for unimplemented! to clarify use) - #65040 (syntax: more cleanups in item and function signature parsing) - #65046 (Make `Cell::new` method come first in documentation) - #65098 (Add long error explanation for E0561) - #65150 (Suggest dereferencing boolean reference when used in 'if' or 'while') - #65154 (Fix const generic arguments not displaying in types mismatch diagnostic) - #65181 (fix bug in folding for constants) - #65187 (use 'invalid argument' for vxWorks) Failed merges: - #65179 (Add long error explanation for E0567) r? @ghost
This commit is contained in:
commit
1e1f25e31b
24 changed files with 469 additions and 309 deletions
|
@ -229,52 +229,6 @@ pub struct Cell<T: ?Sized> {
|
|||
value: UnsafeCell<T>,
|
||||
}
|
||||
|
||||
impl<T:Copy> Cell<T> {
|
||||
/// Returns a copy of the contained value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::cell::Cell;
|
||||
///
|
||||
/// let c = Cell::new(5);
|
||||
///
|
||||
/// let five = c.get();
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn get(&self) -> T {
|
||||
unsafe{ *self.value.get() }
|
||||
}
|
||||
|
||||
/// Updates the contained value using a function and returns the new value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(cell_update)]
|
||||
///
|
||||
/// use std::cell::Cell;
|
||||
///
|
||||
/// let c = Cell::new(5);
|
||||
/// let new = c.update(|x| x + 1);
|
||||
///
|
||||
/// assert_eq!(new, 6);
|
||||
/// assert_eq!(c.get(), 6);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "cell_update", issue = "50186")]
|
||||
pub fn update<F>(&self, f: F) -> T
|
||||
where
|
||||
F: FnOnce(T) -> T,
|
||||
{
|
||||
let old = self.get();
|
||||
let new = f(old);
|
||||
self.set(new);
|
||||
new
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
unsafe impl<T: ?Sized> Send for Cell<T> where T: Send {}
|
||||
|
||||
|
@ -448,6 +402,52 @@ impl<T> Cell<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T:Copy> Cell<T> {
|
||||
/// Returns a copy of the contained value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::cell::Cell;
|
||||
///
|
||||
/// let c = Cell::new(5);
|
||||
///
|
||||
/// let five = c.get();
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn get(&self) -> T {
|
||||
unsafe{ *self.value.get() }
|
||||
}
|
||||
|
||||
/// Updates the contained value using a function and returns the new value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(cell_update)]
|
||||
///
|
||||
/// use std::cell::Cell;
|
||||
///
|
||||
/// let c = Cell::new(5);
|
||||
/// let new = c.update(|x| x + 1);
|
||||
///
|
||||
/// assert_eq!(new, 6);
|
||||
/// assert_eq!(c.get(), 6);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "cell_update", issue = "50186")]
|
||||
pub fn update<F>(&self, f: F) -> T
|
||||
where
|
||||
F: FnOnce(T) -> T,
|
||||
{
|
||||
let old = self.get();
|
||||
let new = f(old);
|
||||
self.set(new);
|
||||
new
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Cell<T> {
|
||||
/// Returns a raw pointer to the underlying data in this cell.
|
||||
///
|
||||
|
|
|
@ -520,18 +520,20 @@ macro_rules! unreachable {
|
|||
});
|
||||
}
|
||||
|
||||
/// Indicates unfinished code.
|
||||
/// Indicates unfinished code by panicking with a message of "not yet implemented".
|
||||
///
|
||||
/// This can be useful if you are prototyping and are just looking to have your
|
||||
/// code type-check, or if you're implementing a trait that requires multiple
|
||||
/// methods, and you're only planning on using one of them.
|
||||
/// This allows the your code to type-check, which is useful if you are prototyping or
|
||||
/// implementing a trait that requires multiple methods which you don't plan of using all of.
|
||||
///
|
||||
/// There is no difference between `unimplemented!` and `todo!` apart from the
|
||||
/// name.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This will always [panic!](macro.panic.html)
|
||||
/// This will always [panic!](macro.panic.html) because `unimplemented!` is just a
|
||||
/// shorthand for `panic!` with a fixed, specific message.
|
||||
///
|
||||
/// Like `panic!`, this macro has a second form for displaying custom values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -539,38 +541,53 @@ macro_rules! unreachable {
|
|||
///
|
||||
/// ```
|
||||
/// trait Foo {
|
||||
/// fn bar(&self);
|
||||
/// fn bar(&self) -> u8;
|
||||
/// fn baz(&self);
|
||||
/// fn qux(&self) -> Result<u64, ()>;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// We want to implement `Foo` on one of our types, but we also want to work on
|
||||
/// just `bar()` first. In order for our code to compile, we need to implement
|
||||
/// `baz()`, so we can use `unimplemented!`:
|
||||
/// We want to implement `Foo` for 'MyStruct', but so far we only know how to
|
||||
/// implement the `bar()` function. `baz()` and `qux()` will still need to be defined
|
||||
/// in our implementation of `Foo`, but we can use `unimplemented!` in their definitions
|
||||
/// to allow our code to compile.
|
||||
///
|
||||
/// In the meantime, we want to have our program stop running once these
|
||||
/// unimplemented functions are reached.
|
||||
///
|
||||
/// ```
|
||||
/// # trait Foo {
|
||||
/// # fn bar(&self);
|
||||
/// # fn bar(&self) -> u8;
|
||||
/// # fn baz(&self);
|
||||
/// # fn qux(&self) -> Result<u64, ()>;
|
||||
/// # }
|
||||
/// struct MyStruct;
|
||||
///
|
||||
/// impl Foo for MyStruct {
|
||||
/// fn bar(&self) {
|
||||
/// // implementation goes here
|
||||
/// fn bar(&self) -> u8 {
|
||||
/// 1 + 1
|
||||
/// }
|
||||
///
|
||||
/// fn baz(&self) {
|
||||
/// // let's not worry about implementing baz() for now
|
||||
/// // We aren't sure how to even start writing baz yet,
|
||||
/// // so we have no logic here at all.
|
||||
/// // This will display "thread 'main' panicked at 'not yet implemented'".
|
||||
/// unimplemented!();
|
||||
/// }
|
||||
///
|
||||
/// fn qux(&self) -> Result<u64, ()> {
|
||||
/// let n = self.bar();
|
||||
/// // We have some logic here,
|
||||
/// // so we can use unimplemented! to display what we have so far.
|
||||
/// // This will display:
|
||||
/// // "thread 'main' panicked at 'not yet implemented: we need to divide by 2'".
|
||||
/// unimplemented!("we need to divide by {}", n);
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let s = MyStruct;
|
||||
/// s.bar();
|
||||
///
|
||||
/// // we aren't even using baz() yet, so this is fine.
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
|
|
|
@ -935,6 +935,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
.filter(|(a, b)| a == b)
|
||||
.count();
|
||||
let len = sub1.len() - common_default_params;
|
||||
let consts_offset = len - sub1.consts().count();
|
||||
|
||||
// Only draw `<...>` if there're lifetime/type arguments.
|
||||
if len > 0 {
|
||||
|
@ -981,7 +982,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
// ^ elided type as this type argument was the same in both sides
|
||||
let type_arguments = sub1.types().zip(sub2.types());
|
||||
let regions_len = sub1.regions().count();
|
||||
for (i, (ta1, ta2)) in type_arguments.take(len).enumerate() {
|
||||
let num_display_types = consts_offset - regions_len;
|
||||
for (i, (ta1, ta2)) in type_arguments.take(num_display_types).enumerate() {
|
||||
let i = i + regions_len;
|
||||
if ta1 == ta2 {
|
||||
values.0.push_normal("_");
|
||||
|
@ -994,6 +996,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
self.push_comma(&mut values.0, &mut values.1, len, i);
|
||||
}
|
||||
|
||||
// Do the same for const arguments, if they are equal, do not highlight and
|
||||
// elide them from the output.
|
||||
let const_arguments = sub1.consts().zip(sub2.consts());
|
||||
for (i, (ca1, ca2)) in const_arguments.enumerate() {
|
||||
let i = i + consts_offset;
|
||||
if ca1 == ca2 {
|
||||
values.0.push_normal("_");
|
||||
values.1.push_normal("_");
|
||||
} else {
|
||||
values.0.push_highlighted(ca1.to_string());
|
||||
values.1.push_highlighted(ca2.to_string());
|
||||
}
|
||||
self.push_comma(&mut values.0, &mut values.1, len, i);
|
||||
}
|
||||
|
||||
// Close the type argument bracket.
|
||||
// Only draw `<...>` if there're lifetime/type arguments.
|
||||
if len > 0 {
|
||||
|
|
|
@ -250,7 +250,9 @@ impl FlagComputation {
|
|||
ConstValue::Placeholder(_) => {
|
||||
self.add_flags(TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_CT_PLACEHOLDER);
|
||||
}
|
||||
_ => {},
|
||||
ConstValue::Scalar(_) => { }
|
||||
ConstValue::Slice { data: _, start: _, end: _ } => { }
|
||||
ConstValue::ByRef { alloc: _, offset: _ } => { }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -911,13 +911,15 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
|
|||
}
|
||||
|
||||
fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> bool {
|
||||
if let ty::Const {
|
||||
val: ConstValue::Infer(ty::InferConst::Canonical(debruijn, _)),
|
||||
..
|
||||
} = *ct {
|
||||
debruijn >= self.outer_index
|
||||
} else {
|
||||
false
|
||||
// we don't have a `visit_infer_const` callback, so we have to
|
||||
// hook in here to catch this case (annoying...), but
|
||||
// otherwise we do want to remember to visit the rest of the
|
||||
// const, as it has types/regions embedded in a lot of other
|
||||
// places.
|
||||
match ct.val {
|
||||
ConstValue::Infer(ty::InferConst::Canonical(debruijn, _))
|
||||
if debruijn >= self.outer_index => true,
|
||||
_ => ct.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -689,7 +689,7 @@ pub trait PrettyPrinter<'tcx>:
|
|||
if self.tcx().sess.verbose() {
|
||||
p!(write(
|
||||
" closure_kind_ty={:?} closure_sig_ty={:?}",
|
||||
substs.as_closure().kind(did, self.tcx()),
|
||||
substs.as_closure().kind_ty(did, self.tcx()),
|
||||
substs.as_closure().sig_ty(did, self.tcx())
|
||||
));
|
||||
}
|
||||
|
@ -698,7 +698,9 @@ pub trait PrettyPrinter<'tcx>:
|
|||
},
|
||||
ty::Array(ty, sz) => {
|
||||
p!(write("["), print(ty), write("; "));
|
||||
if let ConstValue::Unevaluated(..) = sz.val {
|
||||
if self.tcx().sess.verbose() {
|
||||
p!(write("{:?}", sz));
|
||||
} else if let ConstValue::Unevaluated(..) = sz.val {
|
||||
// do not try to evalute unevaluated constants. If we are const evaluating an
|
||||
// array length anon const, rustc will (with debug assertions) print the
|
||||
// constant's path. Which will end up here again.
|
||||
|
@ -855,6 +857,11 @@ pub trait PrettyPrinter<'tcx>:
|
|||
) -> Result<Self::Const, Self::Error> {
|
||||
define_scoped_cx!(self);
|
||||
|
||||
if self.tcx().sess.verbose() {
|
||||
p!(write("Const({:?}: {:?})", ct.val, ct.ty));
|
||||
return Ok(self);
|
||||
}
|
||||
|
||||
let u8 = self.tcx().types.u8;
|
||||
if let ty::FnDef(did, substs) = ct.ty.kind {
|
||||
p!(print_value_path(did, substs));
|
||||
|
|
|
@ -2203,7 +2203,9 @@ impl<'tcx> TyS<'tcx> {
|
|||
_ => bug!("cannot convert type `{:?}` to a closure kind", self),
|
||||
},
|
||||
|
||||
Infer(_) => None,
|
||||
// "Bound" types appear in canonical queries when the
|
||||
// closure type is not yet known
|
||||
Bound(..) | Infer(_) => None,
|
||||
|
||||
Error => Some(ty::ClosureKind::Fn),
|
||||
|
||||
|
|
|
@ -286,6 +286,34 @@ fn main() {
|
|||
```
|
||||
"##,
|
||||
|
||||
E0561: r##"
|
||||
A non-ident or non-wildcard pattern has been used as a parameter of a function
|
||||
pointer type.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0561
|
||||
type A1 = fn(mut param: u8); // error!
|
||||
type A2 = fn(¶m: u32); // error!
|
||||
```
|
||||
|
||||
When using an alias over a function type, you cannot e.g. denote a parameter as
|
||||
being mutable.
|
||||
|
||||
To fix the issue, remove patterns (`_` is allowed though). Example:
|
||||
|
||||
```
|
||||
type A1 = fn(param: u8); // ok!
|
||||
type A2 = fn(_: u32); // ok!
|
||||
```
|
||||
|
||||
You can also omit the parameter name:
|
||||
|
||||
```
|
||||
type A3 = fn(i16); // ok!
|
||||
```
|
||||
"##,
|
||||
|
||||
E0571: r##"
|
||||
A `break` statement with an argument appeared in a non-`loop` loop.
|
||||
|
||||
|
@ -503,7 +531,6 @@ Switch to the Rust 2018 edition to use `async fn`.
|
|||
;
|
||||
E0226, // only a single explicit lifetime bound is permitted
|
||||
E0472, // asm! is unsupported on this target
|
||||
E0561, // patterns aren't allowed in function pointer types
|
||||
E0567, // auto traits can not have generic parameters
|
||||
E0568, // auto traits can not have super traits
|
||||
E0666, // nested `impl Trait` is illegal
|
||||
|
|
|
@ -17,10 +17,12 @@ fn evaluate_obligation<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
canonical_goal: CanonicalPredicateGoal<'tcx>,
|
||||
) -> Result<EvaluationResult, OverflowError> {
|
||||
debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal);
|
||||
tcx.infer_ctxt().enter_with_canonical(
|
||||
DUMMY_SP,
|
||||
&canonical_goal,
|
||||
|ref infcx, goal, _canonical_inference_vars| {
|
||||
debug!("evaluate_obligation: goal={:#?}", goal);
|
||||
let ParamEnvAnd {
|
||||
param_env,
|
||||
value: predicate,
|
||||
|
|
|
@ -349,7 +349,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// If the span is from a macro, then it's hard to extract the text
|
||||
// and make a good suggestion, so don't bother.
|
||||
let is_macro = sp.from_expansion();
|
||||
let is_desugaring = match sp.desugaring_kind() {
|
||||
Some(k) => sp.is_desugaring(k),
|
||||
None => false
|
||||
};
|
||||
let is_macro = sp.from_expansion() && !is_desugaring;
|
||||
|
||||
match (&expr.kind, &expected.kind, &checked_ty.kind) {
|
||||
(_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (&exp.kind, &check.kind) {
|
||||
|
|
|
@ -87,6 +87,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) {
|
||||
self.suggest_ref_or_into(&mut err, expr, expected_ty, ty);
|
||||
|
||||
let expr = match &expr.kind {
|
||||
ExprKind::DropTemps(expr) => expr,
|
||||
_ => expr,
|
||||
|
|
|
@ -3112,8 +3112,10 @@ mod tests {
|
|||
|
||||
#[cfg(windows)]
|
||||
let invalid_options = 87; // ERROR_INVALID_PARAMETER
|
||||
#[cfg(unix)]
|
||||
#[cfg(all(unix, not(target_os = "vxworks")))]
|
||||
let invalid_options = "Invalid argument";
|
||||
#[cfg(target_os = "vxworks")]
|
||||
let invalid_options = "invalid argument";
|
||||
|
||||
// Test various combinations of creation modes and access modes.
|
||||
//
|
||||
|
|
|
@ -11,7 +11,7 @@ mod stmt;
|
|||
mod generics;
|
||||
|
||||
use crate::ast::{
|
||||
self, DUMMY_NODE_ID, AttrStyle, Attribute, BindingMode, CrateSugar, FnDecl, Ident,
|
||||
self, DUMMY_NODE_ID, AttrStyle, Attribute, BindingMode, CrateSugar, Ident,
|
||||
IsAsync, MacDelimiter, Mutability, Param, StrStyle, SelfKind, TyKind, Visibility,
|
||||
VisibilityKind, Unsafety,
|
||||
};
|
||||
|
@ -56,6 +56,17 @@ crate enum BlockMode {
|
|||
Ignore,
|
||||
}
|
||||
|
||||
/// The parsing configuration used to parse a parameter list (see `parse_fn_params`).
|
||||
struct ParamCfg {
|
||||
/// Is `self` is allowed as the first parameter?
|
||||
is_self_allowed: bool,
|
||||
/// Is `...` allowed as the tail of the parameter list?
|
||||
allow_c_variadic: bool,
|
||||
/// `is_name_required` decides if, per-parameter,
|
||||
/// the parameter must have a pattern or just a type.
|
||||
is_name_required: fn(&token::Token) -> bool,
|
||||
}
|
||||
|
||||
/// Like `maybe_whole_expr`, but for things other than expressions.
|
||||
#[macro_export]
|
||||
macro_rules! maybe_whole {
|
||||
|
@ -1094,26 +1105,18 @@ impl<'a> Parser<'a> {
|
|||
res
|
||||
}
|
||||
|
||||
fn parse_fn_params(
|
||||
&mut self,
|
||||
named_params: bool,
|
||||
allow_c_variadic: bool,
|
||||
) -> PResult<'a, Vec<Param>> {
|
||||
/// Parses the parameter list of a function, including the `(` and `)` delimiters.
|
||||
fn parse_fn_params(&mut self, mut cfg: ParamCfg) -> PResult<'a, Vec<Param>> {
|
||||
let sp = self.token.span;
|
||||
let do_not_enforce_named_params_for_c_variadic = |token: &token::Token| {
|
||||
match token.kind {
|
||||
token::DotDotDot => false,
|
||||
_ => named_params,
|
||||
}
|
||||
};
|
||||
let is_trait_item = cfg.is_self_allowed;
|
||||
let mut c_variadic = false;
|
||||
// Parse the arguments, starting out with `self` being possibly allowed...
|
||||
let (params, _) = self.parse_paren_comma_seq(|p| {
|
||||
match p.parse_param_general(
|
||||
false,
|
||||
false,
|
||||
allow_c_variadic,
|
||||
do_not_enforce_named_params_for_c_variadic,
|
||||
) {
|
||||
let param = p.parse_param_general(&cfg, is_trait_item);
|
||||
// ...now that we've parsed the first argument, `self` is no longer allowed.
|
||||
cfg.is_self_allowed = false;
|
||||
|
||||
match param {
|
||||
Ok(param) => Ok(
|
||||
if let TyKind::CVarArgs = param.ty.kind {
|
||||
c_variadic = true;
|
||||
|
@ -1144,7 +1147,10 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
})?;
|
||||
|
||||
let params: Vec<_> = params.into_iter().filter_map(|x| x).collect();
|
||||
let mut params: Vec<_> = params.into_iter().filter_map(|x| x).collect();
|
||||
|
||||
// Replace duplicated recovered params with `_` pattern to avoid unecessary errors.
|
||||
self.deduplicate_recovered_params_names(&mut params);
|
||||
|
||||
if c_variadic && params.len() <= 1 {
|
||||
self.span_err(
|
||||
|
@ -1156,79 +1162,53 @@ impl<'a> Parser<'a> {
|
|||
Ok(params)
|
||||
}
|
||||
|
||||
/// Parses the parameter list and result type of a function that may have a `self` parameter.
|
||||
fn parse_fn_decl_with_self(
|
||||
&mut self,
|
||||
is_name_required: impl Copy + Fn(&token::Token) -> bool,
|
||||
) -> PResult<'a, P<FnDecl>> {
|
||||
// Parse the arguments, starting out with `self` being allowed...
|
||||
let mut is_self_allowed = true;
|
||||
let (mut inputs, _): (Vec<_>, _) = self.parse_paren_comma_seq(|p| {
|
||||
let res = p.parse_param_general(is_self_allowed, true, false, is_name_required);
|
||||
// ...but now that we've parsed the first argument, `self` is no longer allowed.
|
||||
is_self_allowed = false;
|
||||
res
|
||||
})?;
|
||||
|
||||
// Replace duplicated recovered params with `_` pattern to avoid unecessary errors.
|
||||
self.deduplicate_recovered_params_names(&mut inputs);
|
||||
|
||||
Ok(P(FnDecl {
|
||||
inputs,
|
||||
output: self.parse_ret_ty(true)?,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Skips unexpected attributes and doc comments in this position and emits an appropriate
|
||||
/// error.
|
||||
/// This version of parse param doesn't necessarily require identifier names.
|
||||
fn parse_param_general(
|
||||
&mut self,
|
||||
is_self_allowed: bool,
|
||||
is_trait_item: bool,
|
||||
allow_c_variadic: bool,
|
||||
is_name_required: impl Fn(&token::Token) -> bool,
|
||||
) -> PResult<'a, Param> {
|
||||
fn parse_param_general(&mut self, cfg: &ParamCfg, is_trait_item: bool) -> PResult<'a, Param> {
|
||||
let lo = self.token.span;
|
||||
let attrs = self.parse_outer_attributes()?;
|
||||
|
||||
// Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
|
||||
if let Some(mut param) = self.parse_self_param()? {
|
||||
param.attrs = attrs.into();
|
||||
return if is_self_allowed {
|
||||
return if cfg.is_self_allowed {
|
||||
Ok(param)
|
||||
} else {
|
||||
self.recover_bad_self_param(param, is_trait_item)
|
||||
};
|
||||
}
|
||||
|
||||
let is_name_required = is_name_required(&self.token);
|
||||
let is_name_required = match self.token.kind {
|
||||
token::DotDotDot => false,
|
||||
_ => (cfg.is_name_required)(&self.token),
|
||||
};
|
||||
let (pat, ty) = if is_name_required || self.is_named_param() {
|
||||
debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
|
||||
|
||||
let pat = self.parse_fn_param_pat()?;
|
||||
if let Err(mut err) = self.expect(&token::Colon) {
|
||||
if let Some(ident) = self.parameter_without_type(
|
||||
return if let Some(ident) = self.parameter_without_type(
|
||||
&mut err,
|
||||
pat,
|
||||
is_name_required,
|
||||
is_self_allowed,
|
||||
cfg.is_self_allowed,
|
||||
is_trait_item,
|
||||
) {
|
||||
err.emit();
|
||||
return Ok(dummy_arg(ident));
|
||||
Ok(dummy_arg(ident))
|
||||
} else {
|
||||
return Err(err);
|
||||
}
|
||||
Err(err)
|
||||
};
|
||||
}
|
||||
|
||||
self.eat_incorrect_doc_comment_for_param_type();
|
||||
(pat, self.parse_ty_common(true, true, allow_c_variadic)?)
|
||||
(pat, self.parse_ty_common(true, true, cfg.allow_c_variadic)?)
|
||||
} else {
|
||||
debug!("parse_param_general ident_to_pat");
|
||||
let parser_snapshot_before_ty = self.clone();
|
||||
self.eat_incorrect_doc_comment_for_param_type();
|
||||
let mut ty = self.parse_ty_common(true, true, allow_c_variadic);
|
||||
let mut ty = self.parse_ty_common(true, true, cfg.allow_c_variadic);
|
||||
if ty.is_ok() && self.token != token::Comma &&
|
||||
self.token != token::CloseDelim(token::Paren) {
|
||||
// This wasn't actually a type, but a pattern looking like a type,
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use super::{Parser, PResult, PathStyle, SemiColonMode, BlockMode};
|
||||
use super::{Parser, PResult, PathStyle, SemiColonMode, BlockMode, ParamCfg};
|
||||
|
||||
use crate::maybe_whole;
|
||||
use crate::ptr::P;
|
||||
use crate::ast::{
|
||||
self, DUMMY_NODE_ID, Ident, Attribute, AttrStyle,
|
||||
Item, ItemKind, ImplItem, TraitItem, TraitItemKind,
|
||||
Item, ItemKind, ImplItem, ImplItemKind, TraitItem, TraitItemKind,
|
||||
UseTree, UseTreeKind, PathSegment,
|
||||
IsAuto, Constness, IsAsync, Unsafety, Defaultness,
|
||||
Visibility, VisibilityKind, Mutability, FnDecl, FnHeader, MethodSig, Block,
|
||||
|
@ -98,7 +98,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
let lo = self.token.span;
|
||||
|
||||
let visibility = self.parse_visibility(false)?;
|
||||
let vis = self.parse_visibility(false)?;
|
||||
|
||||
if self.eat_keyword(kw::Use) {
|
||||
// USE ITEM
|
||||
|
@ -106,15 +106,14 @@ impl<'a> Parser<'a> {
|
|||
self.expect(&token::Semi)?;
|
||||
|
||||
let span = lo.to(self.prev_span);
|
||||
let item =
|
||||
self.mk_item(span, Ident::invalid(), item_, visibility, attrs);
|
||||
let item = self.mk_item(span, Ident::invalid(), item_, vis, attrs);
|
||||
return Ok(Some(item));
|
||||
}
|
||||
|
||||
if self.eat_keyword(kw::Extern) {
|
||||
let extern_sp = self.prev_span;
|
||||
if self.eat_keyword(kw::Crate) {
|
||||
return Ok(Some(self.parse_item_extern_crate(lo, visibility, attrs)?));
|
||||
return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?));
|
||||
}
|
||||
|
||||
let opt_abi = self.parse_opt_abi()?;
|
||||
|
@ -128,10 +127,10 @@ impl<'a> Parser<'a> {
|
|||
constness: respan(fn_span, Constness::NotConst),
|
||||
abi: opt_abi.unwrap_or(Abi::C),
|
||||
};
|
||||
return self.parse_item_fn(lo, visibility, attrs, header);
|
||||
return self.parse_item_fn(lo, vis, attrs, header);
|
||||
} else if self.check(&token::OpenDelim(token::Brace)) {
|
||||
return Ok(Some(
|
||||
self.parse_item_foreign_mod(lo, opt_abi, visibility, attrs, extern_sp)?,
|
||||
self.parse_item_foreign_mod(lo, opt_abi, vis, attrs, extern_sp)?,
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -142,16 +141,14 @@ impl<'a> Parser<'a> {
|
|||
self.bump();
|
||||
// STATIC ITEM
|
||||
let m = self.parse_mutability();
|
||||
let (ident, item_, extra_attrs) = self.parse_item_const(Some(m))?;
|
||||
let span = lo.to(self.prev_span);
|
||||
let attrs = maybe_append(attrs, extra_attrs);
|
||||
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
|
||||
let info = self.parse_item_const(Some(m))?;
|
||||
return self.mk_item_with_info(attrs, lo, vis, info);
|
||||
}
|
||||
|
||||
if self.eat_keyword(kw::Const) {
|
||||
let const_span = self.prev_span;
|
||||
if [kw::Fn, kw::Unsafe, kw::Extern].iter().any(|k| self.check_keyword(*k)) {
|
||||
// CONST FUNCTION ITEM
|
||||
|
||||
let unsafety = self.parse_unsafety();
|
||||
|
||||
if self.check_keyword(kw::Extern) {
|
||||
|
@ -160,7 +157,7 @@ impl<'a> Parser<'a> {
|
|||
);
|
||||
}
|
||||
let abi = self.parse_extern_abi()?;
|
||||
self.bump(); // 'fn'
|
||||
self.bump(); // `fn`
|
||||
|
||||
let header = FnHeader {
|
||||
unsafety,
|
||||
|
@ -168,7 +165,7 @@ impl<'a> Parser<'a> {
|
|||
constness: respan(const_span, Constness::Const),
|
||||
abi,
|
||||
};
|
||||
return self.parse_item_fn(lo, visibility, attrs, header);
|
||||
return self.parse_item_fn(lo, vis, attrs, header);
|
||||
}
|
||||
|
||||
// CONST ITEM
|
||||
|
@ -184,10 +181,9 @@ impl<'a> Parser<'a> {
|
|||
)
|
||||
.emit();
|
||||
}
|
||||
let (ident, item_, extra_attrs) = self.parse_item_const(None)?;
|
||||
let span = lo.to(self.prev_span);
|
||||
let attrs = maybe_append(attrs, extra_attrs);
|
||||
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
|
||||
|
||||
let info = self.parse_item_const(None)?;
|
||||
return self.mk_item_with_info(attrs, lo, vis, info);
|
||||
}
|
||||
|
||||
// Parses `async unsafe? fn`.
|
||||
|
@ -212,40 +208,33 @@ impl<'a> Parser<'a> {
|
|||
constness: respan(fn_span, Constness::NotConst),
|
||||
abi: Abi::Rust,
|
||||
};
|
||||
return self.parse_item_fn(lo, visibility, attrs, header);
|
||||
return self.parse_item_fn(lo, vis, attrs, header);
|
||||
}
|
||||
}
|
||||
|
||||
if self.check_keyword(kw::Unsafe) &&
|
||||
self.is_keyword_ahead(1, &[kw::Trait, kw::Auto])
|
||||
{
|
||||
// UNSAFE TRAIT ITEM
|
||||
self.bump(); // `unsafe`
|
||||
let is_auto = if self.eat_keyword(kw::Trait) {
|
||||
IsAuto::No
|
||||
} else {
|
||||
self.expect_keyword(kw::Auto)?;
|
||||
self.expect_keyword(kw::Trait)?;
|
||||
IsAuto::Yes
|
||||
};
|
||||
let (ident, item_, extra_attrs) = self.parse_item_trait(is_auto, Unsafety::Unsafe)?;
|
||||
let span = lo.to(self.prev_span);
|
||||
let attrs = maybe_append(attrs, extra_attrs);
|
||||
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
|
||||
let info = self.parse_item_trait(Unsafety::Unsafe)?;
|
||||
return self.mk_item_with_info(attrs, lo, vis, info);
|
||||
}
|
||||
|
||||
if self.check_keyword(kw::Impl) ||
|
||||
self.check_keyword(kw::Unsafe) &&
|
||||
self.is_keyword_ahead(1, &[kw::Impl]) ||
|
||||
self.check_keyword(kw::Default) &&
|
||||
self.is_keyword_ahead(1, &[kw::Impl, kw::Unsafe]) {
|
||||
self.is_keyword_ahead(1, &[kw::Impl, kw::Unsafe])
|
||||
{
|
||||
// IMPL ITEM
|
||||
let defaultness = self.parse_defaultness();
|
||||
let unsafety = self.parse_unsafety();
|
||||
self.expect_keyword(kw::Impl)?;
|
||||
let (ident, item_, extra_attrs) = self.parse_item_impl(unsafety, defaultness)?;
|
||||
let span = lo.to(self.prev_span);
|
||||
let attrs = maybe_append(attrs, extra_attrs);
|
||||
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
|
||||
let info = self.parse_item_impl(unsafety, defaultness)?;
|
||||
return self.mk_item_with_info(attrs, lo, vis, info);
|
||||
}
|
||||
|
||||
if self.check_keyword(kw::Fn) {
|
||||
// FUNCTION ITEM
|
||||
self.bump();
|
||||
|
@ -256,10 +245,12 @@ impl<'a> Parser<'a> {
|
|||
constness: respan(fn_span, Constness::NotConst),
|
||||
abi: Abi::Rust,
|
||||
};
|
||||
return self.parse_item_fn(lo, visibility, attrs, header);
|
||||
return self.parse_item_fn(lo, vis, attrs, header);
|
||||
}
|
||||
|
||||
if self.check_keyword(kw::Unsafe)
|
||||
&& self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) {
|
||||
&& self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace))
|
||||
{
|
||||
// UNSAFE FUNCTION ITEM
|
||||
self.bump(); // `unsafe`
|
||||
// `{` is also expected after `unsafe`; in case of error, include it in the diagnostic.
|
||||
|
@ -273,15 +264,15 @@ impl<'a> Parser<'a> {
|
|||
constness: respan(fn_span, Constness::NotConst),
|
||||
abi,
|
||||
};
|
||||
return self.parse_item_fn(lo, visibility, attrs, header);
|
||||
return self.parse_item_fn(lo, vis, attrs, header);
|
||||
}
|
||||
|
||||
if self.eat_keyword(kw::Mod) {
|
||||
// MODULE ITEM
|
||||
let (ident, item_, extra_attrs) = self.parse_item_mod(&attrs[..])?;
|
||||
let span = lo.to(self.prev_span);
|
||||
let attrs = maybe_append(attrs, extra_attrs);
|
||||
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
|
||||
let info = self.parse_item_mod(&attrs[..])?;
|
||||
return self.mk_item_with_info(attrs, lo, vis, info);
|
||||
}
|
||||
|
||||
if let Some(type_) = self.eat_type() {
|
||||
let (ident, alias, generics) = type_?;
|
||||
// TYPE ITEM
|
||||
|
@ -290,54 +281,44 @@ impl<'a> Parser<'a> {
|
|||
AliasKind::OpaqueTy(bounds) => ItemKind::OpaqueTy(bounds, generics),
|
||||
};
|
||||
let span = lo.to(self.prev_span);
|
||||
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
|
||||
return Ok(Some(self.mk_item(span, ident, item_, vis, attrs)));
|
||||
}
|
||||
|
||||
if self.eat_keyword(kw::Enum) {
|
||||
// ENUM ITEM
|
||||
let (ident, item_, extra_attrs) = self.parse_item_enum()?;
|
||||
let span = lo.to(self.prev_span);
|
||||
let attrs = maybe_append(attrs, extra_attrs);
|
||||
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
|
||||
let info = self.parse_item_enum()?;
|
||||
return self.mk_item_with_info(attrs, lo, vis, info);
|
||||
}
|
||||
|
||||
if self.check_keyword(kw::Trait)
|
||||
|| (self.check_keyword(kw::Auto)
|
||||
&& self.is_keyword_ahead(1, &[kw::Trait]))
|
||||
{
|
||||
let is_auto = if self.eat_keyword(kw::Trait) {
|
||||
IsAuto::No
|
||||
} else {
|
||||
self.expect_keyword(kw::Auto)?;
|
||||
self.expect_keyword(kw::Trait)?;
|
||||
IsAuto::Yes
|
||||
};
|
||||
// TRAIT ITEM
|
||||
let (ident, item_, extra_attrs) = self.parse_item_trait(is_auto, Unsafety::Normal)?;
|
||||
let span = lo.to(self.prev_span);
|
||||
let attrs = maybe_append(attrs, extra_attrs);
|
||||
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
|
||||
let info = self.parse_item_trait(Unsafety::Normal)?;
|
||||
return self.mk_item_with_info(attrs, lo, vis, info);
|
||||
}
|
||||
|
||||
if self.eat_keyword(kw::Struct) {
|
||||
// STRUCT ITEM
|
||||
let (ident, item_, extra_attrs) = self.parse_item_struct()?;
|
||||
let span = lo.to(self.prev_span);
|
||||
let attrs = maybe_append(attrs, extra_attrs);
|
||||
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
|
||||
let info = self.parse_item_struct()?;
|
||||
return self.mk_item_with_info(attrs, lo, vis, info);
|
||||
}
|
||||
|
||||
if self.is_union_item() {
|
||||
// UNION ITEM
|
||||
self.bump();
|
||||
let (ident, item_, extra_attrs) = self.parse_item_union()?;
|
||||
let span = lo.to(self.prev_span);
|
||||
let attrs = maybe_append(attrs, extra_attrs);
|
||||
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
|
||||
let info = self.parse_item_union()?;
|
||||
return self.mk_item_with_info(attrs, lo, vis, info);
|
||||
}
|
||||
if let Some(macro_def) = self.eat_macro_def(&attrs, &visibility, lo)? {
|
||||
|
||||
if let Some(macro_def) = self.eat_macro_def(&attrs, &vis, lo)? {
|
||||
return Ok(Some(macro_def));
|
||||
}
|
||||
|
||||
// Verify whether we have encountered a struct or method definition where the user forgot to
|
||||
// add the `struct` or `fn` keyword after writing `pub`: `pub S {}`
|
||||
if visibility.node.is_pub() &&
|
||||
if vis.node.is_pub() &&
|
||||
self.check_ident() &&
|
||||
self.look_ahead(1, |t| *t != token::Not)
|
||||
{
|
||||
|
@ -428,7 +409,20 @@ impl<'a> Parser<'a> {
|
|||
return Err(err);
|
||||
}
|
||||
}
|
||||
self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, visibility)
|
||||
self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, vis)
|
||||
}
|
||||
|
||||
fn mk_item_with_info(
|
||||
&self,
|
||||
attrs: Vec<Attribute>,
|
||||
lo: Span,
|
||||
vis: Visibility,
|
||||
info: ItemInfo,
|
||||
) -> PResult<'a, Option<P<Item>>> {
|
||||
let (ident, item, extra_attrs) = info;
|
||||
let span = lo.to(self.prev_span);
|
||||
let attrs = maybe_append(attrs, extra_attrs);
|
||||
Ok(Some(self.mk_item(span, ident, item, vis, attrs)))
|
||||
}
|
||||
|
||||
fn recover_first_param(&mut self) -> &'static str {
|
||||
|
@ -727,16 +721,7 @@ impl<'a> Parser<'a> {
|
|||
};
|
||||
(name, kind, generics)
|
||||
} else if self.is_const_item() {
|
||||
// This parses the grammar:
|
||||
// ImplItemConst = "const" Ident ":" Ty "=" Expr ";"
|
||||
self.expect_keyword(kw::Const)?;
|
||||
let name = self.parse_ident()?;
|
||||
self.expect(&token::Colon)?;
|
||||
let typ = self.parse_ty()?;
|
||||
self.expect(&token::Eq)?;
|
||||
let expr = self.parse_expr()?;
|
||||
self.expect(&token::Semi)?;
|
||||
(name, ast::ImplItemKind::Const(typ, expr), Generics::default())
|
||||
self.parse_impl_const()?
|
||||
} else {
|
||||
let (name, inner_attrs, generics, kind) = self.parse_impl_method(&vis, at_end)?;
|
||||
attrs.extend(inner_attrs);
|
||||
|
@ -785,12 +770,25 @@ impl<'a> Parser<'a> {
|
|||
!self.is_keyword_ahead(1, &[kw::Fn, kw::Unsafe])
|
||||
}
|
||||
|
||||
/// This parses the grammar:
|
||||
/// ImplItemConst = "const" Ident ":" Ty "=" Expr ";"
|
||||
fn parse_impl_const(&mut self) -> PResult<'a, (Ident, ImplItemKind, Generics)> {
|
||||
self.expect_keyword(kw::Const)?;
|
||||
let name = self.parse_ident()?;
|
||||
self.expect(&token::Colon)?;
|
||||
let typ = self.parse_ty()?;
|
||||
self.expect(&token::Eq)?;
|
||||
let expr = self.parse_expr()?;
|
||||
self.expect(&token::Semi)?;
|
||||
Ok((name, ImplItemKind::Const(typ, expr), Generics::default()))
|
||||
}
|
||||
|
||||
/// Parses a method or a macro invocation in a trait impl.
|
||||
fn parse_impl_method(
|
||||
&mut self,
|
||||
vis: &Visibility,
|
||||
at_end: &mut bool
|
||||
) -> PResult<'a, (Ident, Vec<Attribute>, Generics, ast::ImplItemKind)> {
|
||||
) -> PResult<'a, (Ident, Vec<Attribute>, Generics, ImplItemKind)> {
|
||||
// FIXME: code copied from `parse_macro_use_or_failure` -- use abstraction!
|
||||
if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(vis), at_end)? {
|
||||
// method macro
|
||||
|
@ -807,14 +805,15 @@ impl<'a> Parser<'a> {
|
|||
/// of a method. The body is not parsed as that differs between `trait`s and `impl`s.
|
||||
fn parse_method_sig(
|
||||
&mut self,
|
||||
is_name_required: impl Copy + Fn(&token::Token) -> bool,
|
||||
is_name_required: fn(&token::Token) -> bool,
|
||||
) -> PResult<'a, (Ident, MethodSig, Generics)> {
|
||||
let header = self.parse_fn_front_matter()?;
|
||||
let (ident, mut generics) = self.parse_fn_header()?;
|
||||
let decl = self.parse_fn_decl_with_self(is_name_required)?;
|
||||
let sig = MethodSig { header, decl };
|
||||
generics.where_clause = self.parse_where_clause()?;
|
||||
Ok((ident, sig, generics))
|
||||
let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
|
||||
is_self_allowed: true,
|
||||
allow_c_variadic: false,
|
||||
is_name_required,
|
||||
})?;
|
||||
Ok((ident, MethodSig { header, decl }, generics))
|
||||
}
|
||||
|
||||
/// Parses all the "front matter" for a `fn` declaration, up to
|
||||
|
@ -849,8 +848,16 @@ impl<'a> Parser<'a> {
|
|||
Ok(FnHeader { constness, unsafety, asyncness, abi })
|
||||
}
|
||||
|
||||
/// Parses `trait Foo { ... }` or `trait Foo = Bar;`.
|
||||
fn parse_item_trait(&mut self, is_auto: IsAuto, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
|
||||
/// Parses `auto? trait Foo { ... }` or `trait Foo = Bar;`.
|
||||
fn parse_item_trait(&mut self, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
|
||||
// Parse optional `auto` prefix.
|
||||
let is_auto = if self.eat_keyword(kw::Auto) {
|
||||
IsAuto::Yes
|
||||
} else {
|
||||
IsAuto::No
|
||||
};
|
||||
|
||||
self.expect_keyword(kw::Trait)?;
|
||||
let ident = self.parse_ident()?;
|
||||
let mut tps = self.parse_generics()?;
|
||||
|
||||
|
@ -935,30 +942,20 @@ impl<'a> Parser<'a> {
|
|||
Ok(item)
|
||||
}
|
||||
|
||||
fn parse_trait_item_(&mut self,
|
||||
at_end: &mut bool,
|
||||
mut attrs: Vec<Attribute>) -> PResult<'a, TraitItem> {
|
||||
fn parse_trait_item_(
|
||||
&mut self,
|
||||
at_end: &mut bool,
|
||||
mut attrs: Vec<Attribute>,
|
||||
) -> PResult<'a, TraitItem> {
|
||||
let lo = self.token.span;
|
||||
self.eat_bad_pub();
|
||||
let (name, kind, generics) = if self.eat_keyword(kw::Type) {
|
||||
self.parse_trait_item_assoc_ty()?
|
||||
} else if self.is_const_item() {
|
||||
self.expect_keyword(kw::Const)?;
|
||||
let ident = self.parse_ident()?;
|
||||
self.expect(&token::Colon)?;
|
||||
let ty = self.parse_ty()?;
|
||||
let default = if self.eat(&token::Eq) {
|
||||
let expr = self.parse_expr()?;
|
||||
self.expect(&token::Semi)?;
|
||||
Some(expr)
|
||||
} else {
|
||||
self.expect(&token::Semi)?;
|
||||
None
|
||||
};
|
||||
(ident, TraitItemKind::Const(ty, default), Generics::default())
|
||||
self.parse_trait_item_const()?
|
||||
} else if let Some(mac) = self.parse_assoc_macro_invoc("trait", None, &mut false)? {
|
||||
// trait item macro.
|
||||
(Ident::invalid(), ast::TraitItemKind::Macro(mac), Generics::default())
|
||||
(Ident::invalid(), TraitItemKind::Macro(mac), Generics::default())
|
||||
} else {
|
||||
// This is somewhat dubious; We don't want to allow
|
||||
// argument names to be left off if there is a definition...
|
||||
|
@ -966,7 +963,7 @@ impl<'a> Parser<'a> {
|
|||
// We don't allow argument names to be left off in edition 2018.
|
||||
let (ident, sig, generics) = self.parse_method_sig(|t| t.span.rust_2018())?;
|
||||
let body = self.parse_trait_method_body(at_end, &mut attrs)?;
|
||||
(ident, ast::TraitItemKind::Method(sig, body), generics)
|
||||
(ident, TraitItemKind::Method(sig, body), generics)
|
||||
};
|
||||
|
||||
Ok(TraitItem {
|
||||
|
@ -980,6 +977,20 @@ impl<'a> Parser<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
fn parse_trait_item_const(&mut self) -> PResult<'a, (Ident, TraitItemKind, Generics)> {
|
||||
self.expect_keyword(kw::Const)?;
|
||||
let ident = self.parse_ident()?;
|
||||
self.expect(&token::Colon)?;
|
||||
let ty = self.parse_ty()?;
|
||||
let default = if self.eat(&token::Eq) {
|
||||
Some(self.parse_expr()?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
self.expect(&token::Semi)?;
|
||||
Ok((ident, TraitItemKind::Const(ty, default), Generics::default()))
|
||||
}
|
||||
|
||||
/// Parse the "body" of a method in a trait item definition.
|
||||
/// This can either be `;` when there's no body,
|
||||
/// or e.g. a block when the method is a provided one.
|
||||
|
@ -1020,8 +1031,7 @@ impl<'a> Parser<'a> {
|
|||
/// Parses the following grammar:
|
||||
///
|
||||
/// TraitItemAssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty]
|
||||
fn parse_trait_item_assoc_ty(&mut self)
|
||||
-> PResult<'a, (Ident, TraitItemKind, Generics)> {
|
||||
fn parse_trait_item_assoc_ty(&mut self) -> PResult<'a, (Ident, TraitItemKind, Generics)> {
|
||||
let ident = self.parse_ident()?;
|
||||
let mut generics = self.parse_generics()?;
|
||||
|
||||
|
@ -1067,21 +1077,13 @@ impl<'a> Parser<'a> {
|
|||
);
|
||||
}
|
||||
|
||||
if self.eat(&token::BinOp(token::Star)) {
|
||||
UseTreeKind::Glob
|
||||
} else {
|
||||
UseTreeKind::Nested(self.parse_use_tree_list()?)
|
||||
}
|
||||
self.parse_use_tree_glob_or_nested()?
|
||||
} else {
|
||||
// `use path::*;` or `use path::{...};` or `use path;` or `use path as bar;`
|
||||
prefix = self.parse_path(PathStyle::Mod)?;
|
||||
|
||||
if self.eat(&token::ModSep) {
|
||||
if self.eat(&token::BinOp(token::Star)) {
|
||||
UseTreeKind::Glob
|
||||
} else {
|
||||
UseTreeKind::Nested(self.parse_use_tree_list()?)
|
||||
}
|
||||
self.parse_use_tree_glob_or_nested()?
|
||||
} else {
|
||||
UseTreeKind::Simple(self.parse_rename()?, DUMMY_NODE_ID, DUMMY_NODE_ID)
|
||||
}
|
||||
|
@ -1090,6 +1092,15 @@ impl<'a> Parser<'a> {
|
|||
Ok(UseTree { prefix, kind, span: lo.to(self.prev_span) })
|
||||
}
|
||||
|
||||
/// Parses `*` or `{...}`.
|
||||
fn parse_use_tree_glob_or_nested(&mut self) -> PResult<'a, UseTreeKind> {
|
||||
Ok(if self.eat(&token::BinOp(token::Star)) {
|
||||
UseTreeKind::Glob
|
||||
} else {
|
||||
UseTreeKind::Nested(self.parse_use_tree_list()?)
|
||||
})
|
||||
}
|
||||
|
||||
/// Parses a `UseTreeKind::Nested(list)`.
|
||||
///
|
||||
/// ```
|
||||
|
@ -1191,38 +1202,34 @@ impl<'a> Parser<'a> {
|
|||
attrs: Vec<Attribute>,
|
||||
header: FnHeader,
|
||||
) -> PResult<'a, Option<P<Item>>> {
|
||||
let allow_c_variadic = header.abi == Abi::C && header.unsafety == Unsafety::Unsafe;
|
||||
let (ident, decl, generics) = self.parse_fn_sig(allow_c_variadic)?;
|
||||
let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
|
||||
is_self_allowed: false,
|
||||
allow_c_variadic: header.abi == Abi::C && header.unsafety == Unsafety::Unsafe,
|
||||
is_name_required: |_| true,
|
||||
})?;
|
||||
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
|
||||
let span = lo.to(self.prev_span);
|
||||
let kind = ItemKind::Fn(decl, header, generics, body);
|
||||
let attrs = maybe_append(attrs, Some(inner_attrs));
|
||||
Ok(Some(self.mk_item(span, ident, kind, vis, attrs)))
|
||||
self.mk_item_with_info(attrs, lo, vis, (ident, kind, Some(inner_attrs)))
|
||||
}
|
||||
|
||||
/// Parse the "signature", including the identifier, parameters, and generics of a function.
|
||||
fn parse_fn_sig(
|
||||
&mut self,
|
||||
allow_c_variadic: bool,
|
||||
) -> PResult<'a, (Ident, P<FnDecl>, Generics)> {
|
||||
let (ident, mut generics) = self.parse_fn_header()?;
|
||||
let decl = self.parse_fn_decl(allow_c_variadic)?;
|
||||
fn parse_fn_sig(&mut self, cfg: ParamCfg) -> PResult<'a, (Ident, P<FnDecl>, Generics)> {
|
||||
let ident = self.parse_ident()?;
|
||||
let mut generics = self.parse_generics()?;
|
||||
let decl = self.parse_fn_decl(cfg, true)?;
|
||||
generics.where_clause = self.parse_where_clause()?;
|
||||
Ok((ident, decl, generics))
|
||||
}
|
||||
|
||||
/// Parses the name and optional generic types of a function header.
|
||||
fn parse_fn_header(&mut self) -> PResult<'a, (Ident, Generics)> {
|
||||
let id = self.parse_ident()?;
|
||||
let generics = self.parse_generics()?;
|
||||
Ok((id, generics))
|
||||
}
|
||||
|
||||
/// Parses the parameter list and result type of a function declaration.
|
||||
fn parse_fn_decl(&mut self, allow_c_variadic: bool) -> PResult<'a, P<FnDecl>> {
|
||||
pub(super) fn parse_fn_decl(
|
||||
&mut self,
|
||||
cfg: ParamCfg,
|
||||
ret_allow_plus: bool,
|
||||
) -> PResult<'a, P<FnDecl>> {
|
||||
Ok(P(FnDecl {
|
||||
inputs: self.parse_fn_params(true, allow_c_variadic)?,
|
||||
output: self.parse_ret_ty(true)?,
|
||||
inputs: self.parse_fn_params(cfg)?,
|
||||
output: self.parse_ret_ty(ret_allow_plus)?,
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -1346,7 +1353,11 @@ impl<'a> Parser<'a> {
|
|||
extern_sp: Span,
|
||||
) -> PResult<'a, ForeignItem> {
|
||||
self.expect_keyword(kw::Fn)?;
|
||||
let (ident, decl, generics) = self.parse_fn_sig(true)?;
|
||||
let (ident, decl, generics) = self.parse_fn_sig(super::ParamCfg {
|
||||
is_self_allowed: false,
|
||||
allow_c_variadic: true,
|
||||
is_name_required: |_| true,
|
||||
})?;
|
||||
let span = lo.to(self.token.span);
|
||||
self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?;
|
||||
Ok(ast::ForeignItem {
|
||||
|
|
|
@ -4,13 +4,11 @@ use crate::{maybe_whole, maybe_recover_from_interpolated_ty_qpath};
|
|||
use crate::ptr::P;
|
||||
use crate::ast::{self, Ty, TyKind, MutTy, BareFnTy, FunctionRetTy, GenericParam, Lifetime, Ident};
|
||||
use crate::ast::{TraitBoundModifier, TraitObjectSyntax, GenericBound, GenericBounds, PolyTraitRef};
|
||||
use crate::ast::{Mutability, AnonConst, FnDecl, Mac};
|
||||
use crate::ast::{Mutability, AnonConst, Mac};
|
||||
use crate::parse::token::{self, Token};
|
||||
use crate::source_map::Span;
|
||||
use crate::symbol::{kw};
|
||||
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use errors::{Applicability, pluralise};
|
||||
|
||||
/// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT<u8, u8>`,
|
||||
|
@ -281,19 +279,14 @@ impl<'a> Parser<'a> {
|
|||
*/
|
||||
|
||||
let unsafety = self.parse_unsafety();
|
||||
let abi = if self.eat_keyword(kw::Extern) {
|
||||
self.parse_opt_abi()?.unwrap_or(Abi::C)
|
||||
} else {
|
||||
Abi::Rust
|
||||
};
|
||||
|
||||
let abi = self.parse_extern_abi()?;
|
||||
self.expect_keyword(kw::Fn)?;
|
||||
let inputs = self.parse_fn_params(false, true)?;
|
||||
let ret_ty = self.parse_ret_ty(false)?;
|
||||
let decl = P(FnDecl {
|
||||
inputs,
|
||||
output: ret_ty,
|
||||
});
|
||||
let cfg = super::ParamCfg {
|
||||
is_self_allowed: false,
|
||||
allow_c_variadic: true,
|
||||
is_name_required: |_| false,
|
||||
};
|
||||
let decl = self.parse_fn_decl(cfg, false)?;
|
||||
Ok(TyKind::BareFn(P(BareFnTy {
|
||||
abi,
|
||||
unsafety,
|
||||
|
|
|
@ -12,8 +12,8 @@ error[E0308]: mismatched types
|
|||
LL | let _: ConstString<"Hello"> = ConstString::<"World">;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ expected `"Hello"`, found `"World"`
|
||||
|
|
||||
= note: expected type `ConstString<>`
|
||||
found type `ConstString<>`
|
||||
= note: expected type `ConstString<"Hello">`
|
||||
found type `ConstString<"World">`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/slice-const-param-mismatch.rs:11:33
|
||||
|
@ -21,8 +21,8 @@ error[E0308]: mismatched types
|
|||
LL | let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ expected `"ℇ㇈↦"`, found `"ℇ㇈↥"`
|
||||
|
|
||||
= note: expected type `ConstString<>`
|
||||
found type `ConstString<>`
|
||||
= note: expected type `ConstString<"ℇ㇈↦">`
|
||||
found type `ConstString<"ℇ㇈↥">`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/slice-const-param-mismatch.rs:13:33
|
||||
|
@ -30,8 +30,8 @@ error[E0308]: mismatched types
|
|||
LL | let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">;
|
||||
| ^^^^^^^^^^^^^^^^^^^^ expected `b"AAA"`, found `b"BBB"`
|
||||
|
|
||||
= note: expected type `ConstBytes<>`
|
||||
found type `ConstBytes<>`
|
||||
= note: expected type `ConstBytes<b"AAA">`
|
||||
found type `ConstBytes<b"BBB">`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
19
src/test/ui/const-generics/types-mismatch-const-args.rs
Normal file
19
src/test/ui/const-generics/types-mismatch-const-args.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
#![feature(const_generics)]
|
||||
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
|
||||
|
||||
// tests the diagnostic output of type mismatches for types that have const generics arguments.
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
struct A<'a, T, const X: u32, const Y: u32> {
|
||||
data: PhantomData<&'a T>
|
||||
}
|
||||
|
||||
fn a<'a, 'b>() {
|
||||
let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data: PhantomData };
|
||||
//~^ ERROR mismatched types
|
||||
let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData };
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
||||
pub fn main() {}
|
29
src/test/ui/const-generics/types-mismatch-const-args.stderr
Normal file
29
src/test/ui/const-generics/types-mismatch-const-args.stderr
Normal file
|
@ -0,0 +1,29 @@
|
|||
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
|
||||
--> $DIR/types-mismatch-const-args.rs:1:12
|
||||
|
|
||||
LL | #![feature(const_generics)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/types-mismatch-const-args.rs:13:41
|
||||
|
|
||||
LL | let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data: PhantomData };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2u32`, found `4u32`
|
||||
|
|
||||
= note: expected type `A<'_, _, 2u32, _>`
|
||||
found type `A<'_, _, 4u32, _>`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/types-mismatch-const-args.rs:15:41
|
||||
|
|
||||
LL | let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u16, found u32
|
||||
|
|
||||
= note: expected type `A<'a, u16, _, _>`
|
||||
found type `A<'b, u32, _, _>`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
|
@ -2,7 +2,10 @@ error[E0308]: mismatched types
|
|||
--> $DIR/if-no-match-bindings.rs:18:8
|
||||
|
|
||||
LL | if b_ref() {}
|
||||
| ^^^^^^^ expected bool, found &bool
|
||||
| ^^^^^^^
|
||||
| |
|
||||
| expected bool, found &bool
|
||||
| help: consider dereferencing the borrow: `*b_ref()`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found type `&bool`
|
||||
|
@ -11,7 +14,10 @@ error[E0308]: mismatched types
|
|||
--> $DIR/if-no-match-bindings.rs:19:8
|
||||
|
|
||||
LL | if b_mut_ref() {}
|
||||
| ^^^^^^^^^^^ expected bool, found &mut bool
|
||||
| ^^^^^^^^^^^
|
||||
| |
|
||||
| expected bool, found &mut bool
|
||||
| help: consider dereferencing the borrow: `*b_mut_ref()`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found type `&mut bool`
|
||||
|
@ -20,7 +26,10 @@ error[E0308]: mismatched types
|
|||
--> $DIR/if-no-match-bindings.rs:20:8
|
||||
|
|
||||
LL | if &true {}
|
||||
| ^^^^^ expected bool, found &bool
|
||||
| ^^^^^
|
||||
| |
|
||||
| expected bool, found &bool
|
||||
| help: consider dereferencing the borrow: `*&true`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found type `&bool`
|
||||
|
@ -29,7 +38,10 @@ error[E0308]: mismatched types
|
|||
--> $DIR/if-no-match-bindings.rs:21:8
|
||||
|
|
||||
LL | if &mut true {}
|
||||
| ^^^^^^^^^ expected bool, found &mut bool
|
||||
| ^^^^^^^^^
|
||||
| |
|
||||
| expected bool, found &mut bool
|
||||
| help: consider dereferencing the borrow: `*&mut true`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found type `&mut bool`
|
||||
|
@ -38,7 +50,10 @@ error[E0308]: mismatched types
|
|||
--> $DIR/if-no-match-bindings.rs:24:11
|
||||
|
|
||||
LL | while b_ref() {}
|
||||
| ^^^^^^^ expected bool, found &bool
|
||||
| ^^^^^^^
|
||||
| |
|
||||
| expected bool, found &bool
|
||||
| help: consider dereferencing the borrow: `*b_ref()`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found type `&bool`
|
||||
|
@ -47,7 +62,10 @@ error[E0308]: mismatched types
|
|||
--> $DIR/if-no-match-bindings.rs:25:11
|
||||
|
|
||||
LL | while b_mut_ref() {}
|
||||
| ^^^^^^^^^^^ expected bool, found &mut bool
|
||||
| ^^^^^^^^^^^
|
||||
| |
|
||||
| expected bool, found &mut bool
|
||||
| help: consider dereferencing the borrow: `*b_mut_ref()`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found type `&mut bool`
|
||||
|
@ -56,7 +74,10 @@ error[E0308]: mismatched types
|
|||
--> $DIR/if-no-match-bindings.rs:26:11
|
||||
|
|
||||
LL | while &true {}
|
||||
| ^^^^^ expected bool, found &bool
|
||||
| ^^^^^
|
||||
| |
|
||||
| expected bool, found &bool
|
||||
| help: consider dereferencing the borrow: `*&true`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found type `&bool`
|
||||
|
@ -65,7 +86,10 @@ error[E0308]: mismatched types
|
|||
--> $DIR/if-no-match-bindings.rs:27:11
|
||||
|
|
||||
LL | while &mut true {}
|
||||
| ^^^^^^^^^ expected bool, found &mut bool
|
||||
| ^^^^^^^^^
|
||||
| |
|
||||
| expected bool, found &mut bool
|
||||
| help: consider dereferencing the borrow: `*&mut true`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found type `&mut bool`
|
||||
|
|
|
@ -18,5 +18,5 @@ LL | m!((bad, pat));
|
|||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0130, E0642.
|
||||
Some errors have detailed explanations: E0130, E0561, E0642.
|
||||
For more information about an error, try `rustc --explain E0130`.
|
||||
|
|
|
@ -30,4 +30,5 @@ LL | type A2 = fn(&arg: u8);
|
|||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0130`.
|
||||
Some errors have detailed explanations: E0130, E0561.
|
||||
For more information about an error, try `rustc --explain E0130`.
|
||||
|
|
|
@ -3,6 +3,7 @@ struct S;
|
|||
impl S {
|
||||
fn f(*, a: u8) -> u8 {}
|
||||
//~^ ERROR expected parameter name, found `*`
|
||||
//~| ERROR mismatched types
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -4,5 +4,17 @@ error: expected parameter name, found `*`
|
|||
LL | fn f(*, a: u8) -> u8 {}
|
||||
| ^ expected parameter name
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-33413.rs:4:23
|
||||
|
|
||||
LL | fn f(*, a: u8) -> u8 {}
|
||||
| - ^^ expected u8, found ()
|
||||
| |
|
||||
| implicitly returns `()` as its body has no tail or `return` expression
|
||||
|
|
||||
= note: expected type `u8`
|
||||
found type `()`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
|
|
@ -517,7 +517,10 @@ error[E0308]: mismatched types
|
|||
--> $DIR/disallowed-positions.rs:32:8
|
||||
|
|
||||
LL | if &let 0 = 0 {}
|
||||
| ^^^^^^^^^^ expected bool, found &bool
|
||||
| ^^^^^^^^^^
|
||||
| |
|
||||
| expected bool, found &bool
|
||||
| help: consider dereferencing the borrow: `*&let 0 = 0`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found type `&bool`
|
||||
|
@ -702,7 +705,10 @@ error[E0308]: mismatched types
|
|||
--> $DIR/disallowed-positions.rs:96:11
|
||||
|
|
||||
LL | while &let 0 = 0 {}
|
||||
| ^^^^^^^^^^ expected bool, found &bool
|
||||
| ^^^^^^^^^^
|
||||
| |
|
||||
| expected bool, found &bool
|
||||
| help: consider dereferencing the borrow: `*&let 0 = 0`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found type `&bool`
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue