use super::pat::Expected;
-use super::ty::AllowPlus;
+use super::ty::{AllowPlus, IsAsCast};
use super::{
BlockMode, Parser, PathStyle, RecoverColon, RecoverComma, Restrictions, SemiColonMode, SeqSep,
TokenExpectType, TokenType,
}
}
+ /// Swift lets users write `Ty?` to mean `Option<Ty>`. Parse the construct and recover from it.
+ pub(super) fn maybe_recover_from_question_mark(
+ &mut self,
+ ty: P<Ty>,
+ is_as_cast: IsAsCast,
+ ) -> P<Ty> {
+ if let IsAsCast::Yes = is_as_cast {
+ return ty;
+ }
+ if self.token == token::Question {
+ self.bump();
+ self.struct_span_err(self.prev_token.span, "invalid `?` in type")
+ .span_label(self.prev_token.span, "`?` is only allowed on expressions, not types")
+ .multipart_suggestion(
+ "if you meant to express that the type might not contain a value, use the `Option` wrapper type",
+ vec![
+ (ty.span.shrink_to_lo(), "Option<".to_string()),
+ (self.prev_token.span, ">".to_string()),
+ ],
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ self.mk_ty(ty.span.to(self.prev_token.span), TyKind::Err)
+ } else {
+ ty
+ }
+ }
+
pub(super) fn maybe_recover_from_bad_type_plus(
&mut self,
allow_plus: AllowPlus,
// Save the state of the parser before parsing type normally, in case there is a
// LessThan comparison after this cast.
let parser_snapshot_before_type = self.clone();
- let cast_expr = match self.parse_ty_no_plus() {
+ let cast_expr = match self.parse_as_cast_ty() {
Ok(rhs) => mk_expr(self, lhs, rhs),
Err(mut type_err) => {
// Rewind to before attempting to parse the type with generics, to recover
"casts cannot be followed by {}",
match with_postfix.kind {
ExprKind::Index(_, _) => "indexing",
- ExprKind::Try(_) => "?",
+ ExprKind::Try(_) => "`?`",
ExprKind::Field(_, _) => "a field access",
ExprKind::MethodCall(_, _, _) => "a method call",
ExprKind::Call(_, _) => "a function call",
No,
}
+pub(super) enum IsAsCast {
+ Yes,
+ No,
+}
+
/// Signals whether parsing a type should recover `->`.
///
/// More specifically, when parsing a function like:
RecoverQPath::Yes,
RecoverReturnSign::Yes,
None,
+ IsAsCast::No,
)
}
RecoverQPath::Yes,
RecoverReturnSign::Yes,
Some(ty_params),
+ IsAsCast::No,
)
}
RecoverQPath::Yes,
RecoverReturnSign::Yes,
None,
+ IsAsCast::No,
)
}
RecoverQPath::Yes,
RecoverReturnSign::Yes,
None,
+ IsAsCast::No,
)
}
+ /// Parses a type following an `as` cast. Similar to `parse_ty_no_plus`, but signaling origin
+ /// for better diagnostics involving `?`.
+ pub(super) fn parse_as_cast_ty(&mut self) -> PResult<'a, P<Ty>> {
+ self.parse_ty_common(
+ AllowPlus::No,
+ AllowCVariadic::No,
+ RecoverQPath::Yes,
+ RecoverReturnSign::Yes,
+ None,
+ IsAsCast::Yes,
+ )
+ }
/// Parse a type without recovering `:` as `->` to avoid breaking code such as `where fn() : for<'a>`
pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P<Ty>> {
self.parse_ty_common(
RecoverQPath::Yes,
RecoverReturnSign::OnlyFatArrow,
None,
+ IsAsCast::No,
)
}
recover_qpath,
recover_return_sign,
None,
+ IsAsCast::No,
)?;
FnRetTy::Ty(ty)
} else if recover_return_sign.can_recover(&self.token.kind) {
recover_qpath,
recover_return_sign,
None,
+ IsAsCast::No,
)?;
FnRetTy::Ty(ty)
} else {
recover_qpath: RecoverQPath,
recover_return_sign: RecoverReturnSign,
ty_generics: Option<&Generics>,
+ is_as_cast: IsAsCast,
) -> PResult<'a, P<Ty>> {
let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
// Try to recover from use of `+` with incorrect priority.
self.maybe_report_ambiguous_plus(allow_plus, impl_dyn_multi, &ty);
self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?;
+ let ty = self.maybe_recover_from_question_mark(ty, is_as_cast);
self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery)
}
pub fn cast_then_try() -> Result<u64,u64> {
Err(0u64) as Result<u64,u64>?;
- //~^ ERROR: casts cannot be followed by ?
+ //~^ ERROR: casts cannot be followed by `?`
Err(0u64): Result<u64,u64>?;
- //~^ ERROR: casts cannot be followed by ?
+ //~^ ERROR: casts cannot be followed by `?`
Ok(1)
}
LL | static bar2: &[i32] = &((&[1i32,2,3]: &[i32; 3])[0..1]);
| + +
-error: casts cannot be followed by ?
+error: casts cannot be followed by `?`
--> $DIR/issue-35813-postfix-after-cast.rs:119:5
|
LL | Err(0u64) as Result<u64,u64>?;
LL | (Err(0u64) as Result<u64,u64>)?;
| + +
-error: casts cannot be followed by ?
+error: casts cannot be followed by `?`
--> $DIR/issue-35813-postfix-after-cast.rs:121:5
|
LL | Err(0u64): Result<u64,u64>?;
fn f(t:for<>t?)
-//~^ ERROR: expected parameter name
-//~| ERROR: expected one of
-//~| ERROR: expected one of
+//~^ ERROR: expected one of
+//~| ERROR: invalid `?` in type
-error: expected parameter name, found `?`
+error: invalid `?` in type
--> $DIR/issue-84148-1.rs:1:14
|
LL | fn f(t:for<>t?)
- | ^ expected parameter name
-
-error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?`
- --> $DIR/issue-84148-1.rs:1:14
+ | ^ `?` is only allowed on expressions, not types
|
-LL | fn f(t:for<>t?)
- | ^
- | |
- | expected one of `(`, `)`, `+`, `,`, `::`, or `<`
- | help: missing `,`
+help: if you meant to express that the type might not contain a value, use the `Option` wrapper type
+ |
+LL | fn f(t:Option<for<>t>)
+ | +++++++ ~
error: expected one of `->`, `where`, or `{`, found `<eof>`
--> $DIR/issue-84148-1.rs:1:15
LL | fn f(t:for<>t?)
| ^ expected one of `->`, `where`, or `{`
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
// error-pattern: this file contains an unclosed delimiter
-// error-pattern: expected parameter name
-// error-pattern: expected one of
+// error-pattern: invalid `?` in type
fn f(t:for<>t?
error: this file contains an unclosed delimiter
- --> $DIR/issue-84148-2.rs:4:16
+ --> $DIR/issue-84148-2.rs:3:16
|
LL | fn f(t:for<>t?
| - ^
| |
| unclosed delimiter
-error: expected parameter name, found `?`
- --> $DIR/issue-84148-2.rs:4:14
+error: invalid `?` in type
+ --> $DIR/issue-84148-2.rs:3:14
|
LL | fn f(t:for<>t?
- | ^ expected parameter name
-
-error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?`
- --> $DIR/issue-84148-2.rs:4:14
+ | ^ `?` is only allowed on expressions, not types
|
-LL | fn f(t:for<>t?
- | ^
- | |
- | expected one of `(`, `)`, `+`, `,`, `::`, or `<`
- | help: missing `,`
+help: if you meant to express that the type might not contain a value, use the `Option` wrapper type
+ |
+LL | fn f(t:Option<for<>t>
+ | +++++++ ~
error: expected one of `->`, `where`, or `{`, found `<eof>`
- --> $DIR/issue-84148-2.rs:4:16
+ --> $DIR/issue-84148-2.rs:3:16
|
LL | fn f(t:for<>t?
| ^ expected one of `->`, `where`, or `{`
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
--- /dev/null
+// run-rustfix
+
+fn foo() -> Option<i32> { //~ ERROR invalid `?` in type
+ let x: Option<i32> = Some(1); //~ ERROR invalid `?` in type
+ x
+}
+
+fn main() {
+ let _: Option<i32> = foo();
+}
--- /dev/null
+// run-rustfix
+
+fn foo() -> i32? { //~ ERROR invalid `?` in type
+ let x: i32? = Some(1); //~ ERROR invalid `?` in type
+ x
+}
+
+fn main() {
+ let _: Option<i32> = foo();
+}
--- /dev/null
+error: invalid `?` in type
+ --> $DIR/trailing-question-in-type.rs:3:16
+ |
+LL | fn foo() -> i32? {
+ | ^ `?` is only allowed on expressions, not types
+ |
+help: if you meant to express that the type might not contain a value, use the `Option` wrapper type
+ |
+LL | fn foo() -> Option<i32> {
+ | +++++++ ~
+
+error: invalid `?` in type
+ --> $DIR/trailing-question-in-type.rs:4:15
+ |
+LL | let x: i32? = Some(1);
+ | ^ `?` is only allowed on expressions, not types
+ |
+help: if you meant to express that the type might not contain a value, use the `Option` wrapper type
+ |
+LL | let x: Option<i32> = Some(1);
+ | +++++++ ~
+
+error: aborting due to 2 previous errors
+