-
Notifications
You must be signed in to change notification settings - Fork 11.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
upgrade errors advanced function signatures #20663
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ use move_binary_format::file_format::{ | |
AbilitySet, DatatypeTyParameter, EnumDefinitionIndex, FunctionDefinitionIndex, | ||
StructDefinitionIndex, TableIndex, | ||
}; | ||
use move_binary_format::normalized::Type; | ||
use move_binary_format::{ | ||
compatibility::Compatibility, | ||
compatibility_mode::CompatibilityMode, | ||
|
@@ -895,6 +896,36 @@ fn function_lost_public( | |
Ok(diags) | ||
} | ||
|
||
fn format_param( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FWIW, this function will behave more nicely when it comes to allocations if you structure it to accept a buffer to write into, rather than return a string: fn format_params(
param: &Type,
type_params: Vec<SourceName>,
output: &mut String,
secondary: &mut Vec<(Loc, String)>,
) -> Result<(), Error>; Instead of |
||
param: &Type, | ||
type_params: Vec<SourceName>, | ||
secondary: &mut Vec<(Loc, String)>, | ||
) -> Result<String, Error> { | ||
Ok(match param { | ||
Type::TypeParameter(t) => { | ||
let type_param = type_params | ||
.get(*t as usize) | ||
.context("Unable to get type param location")?; | ||
|
||
secondary.push(( | ||
type_param.1, | ||
format!("Type parameter '{}' is defined here", &type_param.0), | ||
)); | ||
type_param.0.to_string() | ||
} | ||
Type::Vector(t) => { | ||
format!("vector<{}>", format_param(t, type_params, secondary)?) | ||
} | ||
Type::MutableReference(t) => { | ||
format!("&mut {}", format_param(t, type_params, secondary)?) | ||
} | ||
Type::Reference(t) => { | ||
format!("&{}", format_param(t, type_params, secondary)?) | ||
} | ||
_ => format!("{}", param), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that this does not handle generic structs and enums (if they contain type parameters, you won't find them and replace them with their type param name). Sorry in advance if I'm pointing something out that you addressed in some later PR, I know this is something we talked about on Wednesday! |
||
}) | ||
} | ||
|
||
/// Return a diagnostic for a function signature mismatch. | ||
/// start by checking the lengths of the parameters and returns and return a diagnostic if they are different | ||
/// if the lengths are the same check each parameter piece wise and return a diagnostic for each mismatch | ||
|
@@ -961,13 +992,25 @@ fn function_signature_mismatch_diag( | |
.context("Unable to get parameter location")? | ||
.1; | ||
|
||
let mut secondary = Vec::new(); | ||
|
||
let old_param = format_param( | ||
old_param, | ||
func_sourcemap.type_parameters.clone(), | ||
&mut secondary, | ||
)?; | ||
let new_param = format_param( | ||
new_param, | ||
func_sourcemap.type_parameters.clone(), | ||
&mut Vec::new(), | ||
)?; | ||
|
||
let label = format!("Unexpected parameter '{new_param}', expected '{old_param}'"); | ||
|
||
diags.add(Diagnostic::new( | ||
Functions_::SignatureMismatch, | ||
( | ||
param_loc, | ||
format!("Unexpected parameter {new_param}, expected {old_param}"), | ||
), | ||
Vec::<(Loc, String)>::new(), | ||
(param_loc, label), | ||
secondary, | ||
vec![ | ||
"Functions are part of a module's public interface \ | ||
and cannot be changed during an upgrade." | ||
|
@@ -1117,23 +1160,31 @@ fn function_signature_mismatch_diag( | |
.context("Unable to get return location")?; | ||
|
||
if old_return != new_return { | ||
let mut secondary = Vec::new(); | ||
|
||
let old_return = format_param( | ||
old_return, | ||
func_sourcemap.type_parameters.clone(), | ||
&mut secondary, | ||
)?; | ||
let new_return = format_param( | ||
new_return, | ||
func_sourcemap.type_parameters.clone(), | ||
&mut Vec::new(), | ||
)?; | ||
|
||
let label = if new_function.return_.len() == 1 { | ||
format!("Unexpected return type '{new_return}', expected '{old_return}'") | ||
} else { | ||
format!( | ||
"Unexpected return type '{new_return}' at position {i}, expected '{old_return}'" | ||
) | ||
}; | ||
|
||
diags.add(Diagnostic::new( | ||
Functions_::SignatureMismatch, | ||
( | ||
*return_, | ||
if new_function.return_.len() == 1 { | ||
format!( | ||
"Unexpected return type {new_return}, \ | ||
expected {old_return}" | ||
) | ||
} else { | ||
format!( | ||
"Unexpected return type {new_return} at \ | ||
position {i}, expected {old_return}" | ||
) | ||
}, | ||
), | ||
Vec::<(Loc, String)>::new(), | ||
(*return_, label), | ||
secondary, | ||
vec![ | ||
"Functions are part of a module's public interface \ | ||
and cannot be changed during an upgrade." | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to this -- in the binary representation, all we see is a type, but we should clarify for the sake of people reading source code.