Fix missing locations from generated handler code.

This commit is contained in:
KtorZ 2024-09-03 20:06:29 +02:00 committed by Kasey
parent 2f33c4a8f4
commit 6a438bc8cd
3 changed files with 132 additions and 41 deletions

View File

@ -565,15 +565,15 @@ impl TypedValidator {
TypedExpr::sequence(&[
TypedExpr::let_(
TypedExpr::local_var(var_context, Type::script_context()),
TypedExpr::local_var(var_context, Type::script_context(), self.location),
TypedPattern::Constructor {
is_record: false,
location: Span::empty(),
name: well_known::SCRIPT_CONTEXT_CONSTRUCTORS[0].to_string(),
arguments: vec![
CallArg::var(var_transaction),
CallArg::var(var_redeemer),
CallArg::var(var_purpose),
CallArg::var(var_transaction, Span::empty()),
CallArg::var(var_redeemer, Span::empty()),
CallArg::var(var_purpose, Span::empty()),
],
module: None,
constructor: PatternConstructor::Record {
@ -587,11 +587,13 @@ impl TypedValidator {
),
},
Type::script_context(),
Span::empty(),
),
TypedExpr::When {
location: Span::empty(),
tipo: Type::bool(),
subject: TypedExpr::local_var(var_purpose, Type::script_purpose()).into(),
subject: TypedExpr::local_var(var_purpose, Type::script_purpose(), Span::empty())
.into(),
clauses: self
.handlers
.iter()
@ -611,13 +613,37 @@ impl TypedValidator {
let transaction = handler.arguments.last().unwrap();
println!("REDEEMER SPAN: {:?}", redeemer.location);
let pattern = match handler.name.as_str() {
"spend" => TypedPattern::spend_purpose(var_purpose_arg, var_datum),
"mint" => TypedPattern::mint_purpose(var_purpose_arg),
"withdraw" => TypedPattern::withdraw_purpose(var_purpose_arg),
"publish" => TypedPattern::publish_purpose(var_purpose_arg),
"propose" => TypedPattern::propose_purpose(var_purpose_arg),
"vote" => TypedPattern::vote_purpose(var_purpose_arg),
"spend" => TypedPattern::spend_purpose(
(var_purpose_arg, purpose_arg.location),
(
var_datum,
datum.map(|x| x.location).unwrap_or(Span::empty()),
),
redeemer.location,
),
"mint" => TypedPattern::mint_purpose(
(var_purpose_arg, purpose_arg.location),
redeemer.location,
),
"withdraw" => TypedPattern::withdraw_purpose(
(var_purpose_arg, purpose_arg.location),
redeemer.location,
),
"publish" => TypedPattern::publish_purpose(
(var_purpose_arg, purpose_arg.location),
redeemer.location,
),
"propose" => TypedPattern::propose_purpose(
(var_purpose_arg, purpose_arg.location),
redeemer.location,
),
"vote" => TypedPattern::vote_purpose(
(var_purpose_arg, purpose_arg.location),
redeemer.location,
),
purpose => {
unreachable!("unexpected/unknown purpose: {:?}", purpose)
}
@ -627,36 +653,52 @@ impl TypedValidator {
// expect redeemer: tipo = __redeemer__
then.push(TypedExpr::flexible_expect(
TypedExpr::local_var(var_redeemer, Type::data()),
TypedExpr::local_var(var_redeemer, Type::data(), redeemer.location),
TypedPattern::var(redeemer.get_variable_name().unwrap_or("_")),
redeemer.tipo.clone(),
redeemer.location,
));
// Cast the datum, if any
if let Some(datum) = datum {
// expect datum: tipo = __datum__
then.push(TypedExpr::flexible_expect(
TypedExpr::local_var(var_datum, Type::option(Type::data())),
TypedExpr::local_var(
var_datum,
Type::option(Type::data()),
datum.location,
),
TypedPattern::var(datum.get_variable_name().unwrap_or("_")),
datum.tipo.clone(),
datum.location,
))
}
// let purpose_arg = __purpose_arg__
if let Some(arg_name) = purpose_arg.get_variable_name() {
then.push(TypedExpr::let_(
TypedExpr::local_var(var_purpose_arg, Type::data()),
TypedExpr::local_var(
var_purpose_arg,
Type::data(),
purpose_arg.location,
),
TypedPattern::var(arg_name),
purpose_arg.tipo.clone(),
purpose_arg.location,
));
}
// let last_arg_name = __transaction__
if let Some(arg_name) = transaction.get_variable_name() {
then.push(TypedExpr::let_(
TypedExpr::local_var(var_transaction, Type::data()),
TypedExpr::local_var(
var_transaction,
Type::data(),
transaction.location,
),
TypedPattern::var(arg_name),
Type::data(),
transaction.location,
));
}
@ -676,14 +718,15 @@ impl TypedValidator {
let then = &[
TypedExpr::let_(
TypedExpr::local_var(var_context, arg.tipo.clone()),
TypedExpr::local_var(var_context, arg.tipo.clone(), arg.location),
arg.get_variable_name().map(TypedPattern::var).unwrap_or(
TypedPattern::Discard {
name: var_context.to_string(),
location: Span::empty(),
location: arg.location,
},
),
arg.tipo.clone(),
arg.location,
),
fallback.body.clone(),
];
@ -879,12 +922,12 @@ impl TypedCallArg {
}
impl CallArg<TypedPattern> {
pub fn var(name: &str) -> Self {
pub fn var(name: &str, location: Span) -> Self {
CallArg {
label: None,
location: Span::empty(),
value: TypedPattern::Var {
location: Span::empty(),
location,
name: name.to_string(),
},
}
@ -1456,10 +1499,15 @@ impl TypedPattern {
}
}
pub fn constructor(name: &str, arguments: &[CallArg<TypedPattern>], tipo: Rc<Type>) -> Self {
pub fn constructor(
name: &str,
arguments: &[CallArg<TypedPattern>],
tipo: Rc<Type>,
location: Span,
) -> Self {
TypedPattern::Constructor {
is_record: false,
location: Span::empty(),
location,
name: name.to_string(),
arguments: arguments.to_vec(),
module: None,
@ -1472,60 +1520,88 @@ impl TypedPattern {
}
}
pub fn mint_purpose(var_purpose_arg: &str) -> Self {
pub fn mint_purpose(
(var_purpose_arg, purpose_span): (&str, Span),
redeemer_span: Span,
) -> Self {
TypedPattern::constructor(
well_known::SCRIPT_PURPOSE_MINT,
&[CallArg::var(var_purpose_arg)],
&[CallArg::var(var_purpose_arg, purpose_span)],
Type::function(vec![Type::byte_array()], Type::script_purpose()),
redeemer_span,
)
}
pub fn spend_purpose(var_purpose_arg: &str, var_datum: &str) -> Self {
pub fn spend_purpose(
(var_purpose_arg, purpose_span): (&str, Span),
(var_datum, datum_span): (&str, Span),
redeemer_span: Span,
) -> Self {
TypedPattern::constructor(
well_known::SCRIPT_PURPOSE_SPEND,
&[CallArg::var(var_purpose_arg), CallArg::var(var_datum)],
&[
CallArg::var(var_purpose_arg, purpose_span),
CallArg::var(var_datum, datum_span),
],
Type::function(
vec![Type::data(), Type::option(Type::data())],
Type::script_purpose(),
),
redeemer_span,
)
}
pub fn withdraw_purpose(var_purpose_arg: &str) -> Self {
pub fn withdraw_purpose(
(var_purpose_arg, purpose_span): (&str, Span),
redeemer_span: Span,
) -> Self {
TypedPattern::constructor(
well_known::SCRIPT_PURPOSE_WITHDRAW,
&[CallArg::var(var_purpose_arg)],
&[CallArg::var(var_purpose_arg, purpose_span)],
Type::function(vec![Type::data()], Type::script_purpose()),
redeemer_span,
)
}
pub fn publish_purpose(var_purpose_arg: &str) -> Self {
pub fn publish_purpose(
(var_purpose_arg, purpose_span): (&str, Span),
redeemer_span: Span,
) -> Self {
TypedPattern::constructor(
well_known::SCRIPT_PURPOSE_PUBLISH,
&[
CallArg::var("__discarded_purpose_ix__"),
CallArg::var(var_purpose_arg),
CallArg::var("__discarded_purpose_ix__", purpose_span),
CallArg::var(var_purpose_arg, purpose_span),
],
Type::function(vec![Type::int(), Type::data()], Type::script_purpose()),
redeemer_span,
)
}
pub fn vote_purpose(var_purpose_arg: &str) -> Self {
pub fn vote_purpose(
(var_purpose_arg, purpose_span): (&str, Span),
redeemer_span: Span,
) -> Self {
TypedPattern::constructor(
well_known::SCRIPT_PURPOSE_VOTE,
&[CallArg::var(var_purpose_arg)],
&[CallArg::var(var_purpose_arg, purpose_span)],
Type::function(vec![Type::data()], Type::script_purpose()),
redeemer_span,
)
}
pub fn propose_purpose(var_purpose_arg: &str) -> Self {
pub fn propose_purpose(
(var_purpose_arg, purpose_span): (&str, Span),
redeemer_span: Span,
) -> Self {
TypedPattern::constructor(
well_known::SCRIPT_PURPOSE_PROPOSE,
&[
CallArg::var("__discarded_purpose_ix__"),
CallArg::var(var_purpose_arg),
CallArg::var("__discarded_purpose_ix__", purpose_span),
CallArg::var(var_purpose_arg, purpose_span),
],
Type::function(vec![Type::int(), Type::data()], Type::script_purpose()),
redeemer_span,
)
}
}

View File

@ -210,20 +210,24 @@ impl TypedExpr {
}
}
pub fn let_(value: Self, pattern: TypedPattern, tipo: Rc<Type>) -> Self {
pub fn let_(value: Self, pattern: TypedPattern, tipo: Rc<Type>, location: Span) -> Self {
TypedExpr::Assignment {
location: Span::empty(),
tipo: tipo.clone(),
value: value.into(),
pattern,
kind: AssignmentKind::let_(),
location,
}
}
// Create an expect assignment, unless the target type is `Data`; then fallback to a let.
pub fn flexible_expect(value: Self, pattern: TypedPattern, tipo: Rc<Type>) -> Self {
pub fn flexible_expect(
value: Self,
pattern: TypedPattern,
tipo: Rc<Type>,
location: Span,
) -> Self {
TypedExpr::Assignment {
location: Span::empty(),
tipo: tipo.clone(),
value: value.into(),
pattern,
@ -232,12 +236,12 @@ impl TypedExpr {
} else {
AssignmentKind::expect()
},
location,
}
}
pub fn local_var(name: &str, tipo: Rc<Type>) -> Self {
pub fn local_var(name: &str, tipo: Rc<Type>, location: Span) -> Self {
TypedExpr::Var {
location: Span::empty(),
constructor: ValueConstructor {
public: true,
variant: ValueConstructorVariant::LocalVariable {
@ -246,6 +250,7 @@ impl TypedExpr {
tipo: tipo.clone(),
},
name: name.to_string(),
location,
}
}

View File

@ -1719,6 +1719,11 @@ pub fn get_src_code_by_span(
span: &Span,
module_src: &IndexMap<&str, &(String, LineNumbers)>,
) -> String {
assert!(
*span != Span::empty(),
"tried to lookup source code from empty location"
);
let (src, _) = module_src
.get(module_name)
.unwrap_or_else(|| panic!("Missing module {module_name}"));
@ -1733,6 +1738,11 @@ pub fn get_line_columns_by_span(
span: &Span,
module_src: &IndexMap<&str, &(String, LineNumbers)>,
) -> LineColumn {
assert!(
*span != Span::empty(),
"tried to lookup line & columns from empty location"
);
let (_, lines) = module_src
.get(module_name)
.unwrap_or_else(|| panic!("Missing module {module_name}"));