Skip to content
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

Improve type inferrence for binary expressions #957

Merged
merged 3 commits into from
May 31, 2021

Conversation

turbolent
Copy link
Member

Description

I wrote a Base64 encoding function for Cadence here:
https://forum.onflow.org/t/base64-encode-in-cadence/1915/7

This currently requires a lot of static type annotations and casts and could be much simplified through the following observations and changes.

  • Currently the contextually expected type (if any) is only used for arithmetic binary expressions.

    However, bitwise binary expressions have the same property that the resulting type must be compatible with the operands.

  • Currently the left expression and the right expression are type checked individually, and each side is provided with the contextually expected type (if any).

    However, the both sides of arithmetic, logical, etc. expressions must have the same type, so if no contextually expected type is present, use the left type as the expected type when checking the right side.

  • The contextually expected type might be less specific. For example, the indexing type for arrays and strings is Integer. This causes an expression like let x = 1 as UInt8; "abc"[x + 1] to fail to type check.

With the following changes, this portion of the example program can be significantly simplified:

  • Before:

    let n = (UInt32(data[i]) << 16 as UInt32)
        + (UInt32(data[i + 1 as Int]) << 8 as UInt32)
        + UInt32(data[i + 2 as Int])
    
    let n1 = (n >> 18 as UInt32) & 63 as UInt32
    let n2 = (n >> 12 as UInt32) & 63 as UInt32
    let n3 = (n >> 6 as UInt32) & 63 as UInt32
    let n4 = n & 63 as UInt32
  • After:

    let n = UInt32(data[i]) << 16
        + UInt32(data[i + 1]) << 8
        + UInt32(data[i + 2])
    
    let n1 = (n >> 18) & 63
    let n2 = (n >> 12) & 63
    let n3 = (n >> 6) & 63
    let n4 = n & 63

Also, improve the tests by

  • Removing the wrapper functions
  • Adding assertions for the resulting types

  • Targeted PR against master branch
  • Linked to Github issue with discussion and accepted design OR link to spec that describes this work
  • Code follows the standards mentioned here
  • Updated relevant documentation
  • Re-reviewed Files changed in the Github PR explorer
  • Added appropriate labels

@turbolent turbolent requested a review from SupunS May 28, 2021 18:57
@turbolent turbolent self-assigned this May 28, 2021
Comment on lines +83 to +84
// If there is no contextually expected type,
// then expect the right type to have the type of the left side.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This enforcement seems sensible 👍

runtime/sema/check_binary_expression.go Outdated Show resolved Hide resolved
Comment on lines +92 to +95
// Also, if there is a contextually expected type,
// but the left type is a subtype and more specific (i.e not the same),
// then use it instead as the expected type for the right type.
// For example, this allows declarations like the following to type-check:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@codecov-commenter
Copy link

codecov-commenter commented May 31, 2021

Codecov Report

Merging #957 (9b9f123) into master (8e3c230) will increase coverage by 0.06%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #957      +/-   ##
==========================================
+ Coverage   75.36%   75.42%   +0.06%     
==========================================
  Files         268      268              
  Lines       32666    32729      +63     
==========================================
+ Hits        24618    24686      +68     
+ Misses       6915     6911       -4     
+ Partials     1133     1132       -1     
Flag Coverage Δ
unittests 75.42% <100.00%> (+0.06%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
runtime/sema/check_binary_expression.go 87.89% <100.00%> (+0.22%) ⬆️
runtime/sema/type.go 88.38% <100.00%> (-0.01%) ⬇️
runtime/sema/ranges.go 100.00% <0.00%> (ø)
runtime/stdlib/builtin.go 95.52% <0.00%> (ø)
runtime/ast/programindices.go 100.00% <0.00%> (ø)
runtime/sema/check_function.go 99.54% <0.00%> (+<0.01%) ⬆️
runtime/sema/check_composite_declaration.go 96.13% <0.00%> (+0.01%) ⬆️
runtime/sema/checker.go 89.96% <0.00%> (+0.01%) ⬆️
runtime/sema/variable_activations.go 94.91% <0.00%> (+0.04%) ⬆️
... and 11 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 8e3c230...9b9f123. Read the comment docs.

@turbolent turbolent merged commit 1757bfe into master May 31, 2021
@turbolent turbolent deleted the bastian/improve-binary-expression-type-inference branch May 31, 2021 18:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants