check_simd(tcx, span, def_id);
}
- // if struct is packed and not aligned, check fields for alignment.
- // Checks for combining packed and align attrs on single struct are done elsewhere.
- if tcx.adt_def(def_id).repr.packed() && tcx.adt_def(def_id).repr.align == 0 {
- check_packed(tcx, span, def_id);
- }
+ check_packed(tcx, span, def_id);
}
fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let def = tcx.adt_def(def_id);
def.destructor(tcx); // force the destructor to be evaluated
check_representable(tcx, span, def_id);
+
+ check_packed(tcx, span, def_id);
}
pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item) {
}
fn check_packed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId) {
- if check_packed_inner(tcx, def_id, &mut Vec::new()) {
- struct_span_err!(tcx.sess, sp, E0588,
- "packed struct cannot transitively contain a `[repr(align)]` struct").emit();
+ if tcx.adt_def(def_id).repr.packed() {
+ if tcx.adt_def(def_id).repr.align > 0 {
+ struct_span_err!(tcx.sess, sp, E0587,
+ "type has conflicting packed and align representation hints").emit();
+ }
+ else if check_packed_inner(tcx, def_id, &mut Vec::new()) {
+ struct_span_err!(tcx.sess, sp, E0588,
+ "packed type cannot transitively contain a `[repr(align)]` type").emit();
+ }
}
}
return false;
}
match t.sty {
- ty::TyAdt(def, substs) if def.is_struct() => {
+ ty::TyAdt(def, substs) if def.is_struct() || def.is_union() => {
if tcx.adt_def(def.did).repr.align > 0 {
return true;
}
fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>)
-> Option<ty::Region<'tcx>> {
let v = match def {
- Some(def) => infer::EarlyBoundRegion(span, def.name, def.issue_32330),
+ Some(def) => infer::EarlyBoundRegion(span, def.name),
None => infer::MiscVariable(span)
};
Some(self.next_region_var(v))
format!("did you mean `{}`?", suggested_field_name));
} else {
err.span_label(field.span, "unknown field");
+ let struct_variant_def = def.struct_variant();
+ let field_names = self.available_field_names(struct_variant_def);
+ if !field_names.is_empty() {
+ err.note(&format!("available fields are: {}",
+ self.name_series_display(field_names)));
+ }
};
}
ty::TyRawPtr(..) => {
// Return an hint about the closest match in field names
fn suggest_field_name(variant: &'tcx ty::VariantDef,
field: &Spanned<ast::Name>,
- skip : Vec<InternedString>)
+ skip: Vec<InternedString>)
-> Option<Symbol> {
let name = field.node.as_str();
let names = variant.fields.iter().filter_map(|field| {
}
});
- // only find fits with at least one matching letter
- find_best_match_for_name(names, &name, Some(name.len()))
+ find_best_match_for_name(names, &name, None)
+ }
+
+ fn available_field_names(&self, variant: &'tcx ty::VariantDef) -> Vec<ast::Name> {
+ let mut available = Vec::new();
+ for field in variant.fields.iter() {
+ let (_, def_scope) = self.tcx.adjust(field.name, variant.did, self.body_id);
+ if field.vis.is_accessible_from(def_scope, self.tcx) {
+ available.push(field.name);
+ }
+ }
+ available
+ }
+
+ fn name_series_display(&self, names: Vec<ast::Name>) -> String {
+ // dynamic limit, to never omit just one field
+ let limit = if names.len() == 6 { 6 } else { 5 };
+ let mut display = names.iter().take(limit)
+ .map(|n| format!("`{}`", n)).collect::<Vec<_>>().join(", ");
+ if names.len() > limit {
+ display = format!("{} ... and {} others", display, names.len() - limit);
+ }
+ display
}
// Check tuple index expressions
format!("field does not exist - did you mean `{}`?", field_name));
} else {
match ty.sty {
- ty::TyAdt(adt, ..) if adt.is_enum() => {
- err.span_label(field.name.span, format!("`{}::{}` does not have this field",
- ty, variant.name));
- }
- _ => {
- err.span_label(field.name.span, format!("`{}` does not have this field", ty));
+ ty::TyAdt(adt, ..) => {
+ if adt.is_enum() {
+ err.span_label(field.name.span,
+ format!("`{}::{}` does not have this field",
+ ty, variant.name));
+ } else {
+ err.span_label(field.name.span,
+ format!("`{}` does not have this field", ty));
+ }
+ let available_field_names = self.available_field_names(variant);
+ if !available_field_names.is_empty() {
+ err.note(&format!("available fields are: {}",
+ self.name_series_display(available_field_names)));
+ }
}
+ _ => bug!("non-ADT passed to report_unknown_field")
}
};
err.emit();
Ok(def) => def,
Err(error) => {
let def = match error {
- method::MethodError::PrivateMatch(def) => def,
+ method::MethodError::PrivateMatch(def, _) => def,
_ => Def::Err,
};
if item_name != keywords::Invalid.name() {
local: &'gcx hir::Local,
init: &'gcx hir::Expr) -> Ty<'tcx>
{
- let ref_bindings = local.pat.contains_ref_binding();
+ // FIXME(tschottdorf): contains_explicit_ref_binding() must be removed
+ // for #42640.
+ let ref_bindings = local.pat.contains_explicit_ref_binding();
let local_ty = self.local_ty(init.span, local.id);
if let Some(m) = ref_bindings {
ty
}
- /// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether it is
- /// `fn main` if it is a method, `None` otherwise.
+ /// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether a
+ /// suggetion can be made, `None` otherwise.
pub fn get_fn_decl(&self, blk_id: ast::NodeId) -> Option<(hir::FnDecl, bool)> {
// Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
// `while` before reaching it, as block tail returns are not available in them.
name, node: hir::ItemFn(ref decl, ..), ..
}) = parent {
decl.clone().and_then(|decl| {
- // This is less than ideal, it will not present the return type span on any
- // method called `main`, regardless of whether it is actually the entry point.
- Some((decl, name == Symbol::intern("main")))
+ // This is less than ideal, it will not suggest a return type span on any
+ // method called `main`, regardless of whether it is actually the entry point,
+ // but it will still present it as the reason for the expected type.
+ Some((decl, name != Symbol::intern("main")))
})
} else if let Node::NodeTraitItem(&hir::TraitItem {
node: hir::TraitItemKind::Method(hir::MethodSig {
ref decl, ..
}, ..), ..
+ }) = parent {
+ decl.clone().and_then(|decl| {
+ Some((decl, true))
+ })
+ } else if let Node::NodeImplItem(&hir::ImplItem {
+ node: hir::ImplItemKind::Method(hir::MethodSig {
+ ref decl, ..
+ }, ..), ..
}) = parent {
decl.clone().and_then(|decl| {
Some((decl, false))
blk_id: ast::NodeId) {
self.suggest_missing_semicolon(err, expression, expected, cause_span);
- if let Some((fn_decl, is_main)) = self.get_fn_decl(blk_id) {
- // `fn main()` must return `()`, do not suggest changing return type
- if !is_main {
- self.suggest_missing_return_type(err, &fn_decl, found);
- }
+ if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
+ self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
}
}
fn suggest_missing_return_type(&self,
err: &mut DiagnosticBuilder<'tcx>,
fn_decl: &hir::FnDecl,
- ty: Ty<'tcx>) {
-
- // Only recommend changing the return type for methods that
+ expected: Ty<'tcx>,
+ found: Ty<'tcx>,
+ can_suggest: bool) {
+ // Only suggest changing the return type for methods that
// haven't set a return type at all (and aren't `fn main()` or an impl).
- if let &hir::FnDecl {
- output: hir::FunctionRetTy::DefaultReturn(span), ..
- } = fn_decl {
- if ty.is_suggestable() {
+ match (&fn_decl.output, found.is_suggestable(), can_suggest) {
+ (&hir::FunctionRetTy::DefaultReturn(span), true, true) => {
err.span_suggestion(span,
"try adding a return type",
- format!("-> {} ", ty));
- } else {
+ format!("-> {} ", found));
+ }
+ (&hir::FunctionRetTy::DefaultReturn(span), false, true) => {
err.span_label(span, "possibly return type missing here?");
}
+ (&hir::FunctionRetTy::DefaultReturn(span), _, _) => {
+ // `fn main()` must return `()`, do not suggest changing return type
+ err.span_label(span, "expected `()` because of default return type");
+ }
+ (&hir::FunctionRetTy::Return(ref ty), _, _) => {
+ // Only point to return type if the expected type is the return type, as if they
+ // are not, the expectation must have been caused by something else.
+ debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.node);
+ let sp = ty.span;
+ let ty = AstConv::ast_ty_to_ty(self, ty);
+ debug!("suggest_missing_return_type: return type sty {:?}", ty.sty);
+ debug!("suggest_missing_return_type: expected type sty {:?}", ty.sty);
+ if ty.sty == expected.sty {
+ err.span_label(sp, format!("expected `{}` because of return type",
+ expected));
+ }
+ }
}
}