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

[Bug]: Go compiler can't convert extern string to seq<char> #2989

Closed
alex-chew opened this issue Nov 4, 2022 · 4 comments
Closed

[Bug]: Go compiler can't convert extern string to seq<char> #2989

alex-chew opened this issue Nov 4, 2022 · 4 comments
Assignees
Labels
breaking-change Any change that will cause existing Dafny codebases to break (excluding verification instability) lang: golang Dafny's transpiler to Go and its runtime part: code-generation Support for transpiling Dafny to another language. If relevant, add a `lang:` tag
Milestone

Comments

@alex-chew
Copy link
Contributor

Dafny version

3.9.1.41027

Code to produce this issue

method Main() {
  var s := Foo();
}

method {:extern "foo"} Foo() returns (s: string)

method Bar() returns (s: string) {
  return "hello";
}

Command to run and results

# With code as written
$ dafny translate Tmp.dfy -t go

Dafny program verifier finished with 1 verified, 0 errors
Tmp.dfy(2,14): Error: Cannot convert from string to seq<char>
Wrote textual form of partial target program to Tmp-go/src/Tmp.go

# If replacing the call to Foo with a call to Bar
$ dafny translate Tmp.dfy -t go

Dafny program verifier finished with 1 verified, 0 errors

What happened?

A call to an extern method returning a string, is not successfully compiled to Golang. The compiler complains that it Cannot convert from string to seq<char>. The same code compiles as expected to C#, Java, Javascript, and Python.

The same happens if the extern method is declared to return seq<char>, which is unsurprising since it is synonymous with string, but then again this seems to matter to the Golang compiler.

What type of Operating System are you seeing the problem on?

Mac

@alex-chew alex-chew added part: code-generation Support for transpiling Dafny to another language. If relevant, add a `lang:` tag lang: golang Dafny's transpiler to Go and its runtime labels Nov 4, 2022
@robin-aws robin-aws self-assigned this Nov 4, 2022
@robin-aws
Copy link
Member

When attempting to reproduce this with a debug source build, I actually hit an exception:

Process terminated. Assertion failed.
   at Microsoft.Dafny.Type.Equal_Improved(Type a, Type b) in /Users/salkeldr/Documents/GitHub/dafny/Source/DafnyCore/AST/Types.cs:line 1149
   at Microsoft.Dafny.Type.SameHead(Type t, Type u) in /Users/salkeldr/Documents/GitHub/dafny/Source/DafnyCore/AST/Types.cs:line 1005
   at Microsoft.Dafny.Compilers.SinglePassCompiler.IsTargetSupertype(Type to, Type from, Boolean typeEqualityOnly) in /Users/salkeldr/Documents/GitHub/dafny/Source/DafnyCore/Compilers/SinglePassCompiler.cs:line 733
   at Microsoft.Dafny.Compilers.SinglePassCompiler.EmitDowncastIfNecessary(Type from, Type to, IToken tok, ConcreteSyntaxTree wr) in /Users/salkeldr/Documents/GitHub/dafny/Source/DafnyCore/Compilers/SinglePassCompiler.cs:line 712
   at Microsoft.Dafny.Compilers.SinglePassCompiler.TrCallStmt(CallStmt s, String receiverReplacement, ConcreteSyntaxTree wr) in /Users/salkeldr/Documents/GitHub/dafny/Source/DafnyCore/Compilers/SinglePassCompiler.cs:line 4173

The root cause is that the Go compiler tries to special-case extern declarations that accept or return string values, attempting to directly map the Dafny string type to the native Go string type, and coerce between them. The problem is that the SpecialNativeType subclass of UserDefinedType used to represent the native Go string type doesn't have all the expected values for a resolved type, which caused the above assertion failure if assertions are checked. In the release build, the symptom is just failing to recognize that two types are actually the same.

@alex-chew
Copy link
Contributor Author

Ah, good catch. I'd seen this while trying to debug, but didn't realize it only appeared with a debug build - I was trying to reproduce this error in the VSCode IDE to no avail.

@robin-aws robin-aws added the breaking-change Any change that will cause existing Dafny codebases to break (excluding verification instability) label Feb 1, 2023
@robin-aws robin-aws added this to the Dafny 4.0 milestone Feb 1, 2023
@robin-aws
Copy link
Member

For the record, the root cause here is that this feature is not deeply and rigorously implemented, and to my knowledge none of the other compilers attempt to support this style of automatic equivalence of types for externs. My strong preference is to remove the implementation, being as careful as necessary about the fact that it is a breaking change. I've flagged this as a breaking change and conservatively added it to the Dafny 4.0 milestone in case we treat it as such.

@hmijail is any of your code depending on this behavior at this point, or would it benefit from the more consistent behavior of a Dafny string appearing as a dafny.Seq of characters in Go code?

@hmijail
Copy link

hmijail commented Feb 2, 2023

We're just getting started with the Go part, so we don't really care at this point.
Also, we're hoping to keep multiple target languages, so consistent behavior would probably be a good thing.

@robin-aws robin-aws removed their assignment Feb 7, 2023
robin-aws added a commit that referenced this issue Feb 28, 2023
…externs (#3647)

Fixes #2989. From my comments on that issue:

> The root cause is that the Go compiler tries to special-case extern
declarations that accept or return string values, attempting to directly
map the Dafny string type to the native Go string type, and coerce
between them. The problem is that the SpecialNativeType subclass of
UserDefinedType used to represent the native Go string type doesn't have
all the expected values for a resolved type, which caused the above
assertion failure if assertions are checked. In the release build, the
symptom is just failing to recognize that two types are actually the
same.

> For the record, the root cause here is that this feature is not deeply
and rigorously implemented, and to my knowledge none of the other
compilers attempt to support this style of automatic equivalence of
types for externs. My strong preference is to remove the implementation,
being as careful as necessary about the fact that it is a breaking
change.

I attempted to rewrite the one test that demonstrates this functionality
(`GoModule.dfy`) to include manual conversions between the two string
types, but I ran into several unrelated issues, and so downgraded the
test to a negative test for now under `Test/wishlist`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking-change Any change that will cause existing Dafny codebases to break (excluding verification instability) lang: golang Dafny's transpiler to Go and its runtime part: code-generation Support for transpiling Dafny to another language. If relevant, add a `lang:` tag
Projects
None yet
Development

No branches or pull requests

3 participants